定制 aliziodev/payid-transactions 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

aliziodev/payid-transactions

最新稳定版本:v0.1.0

Composer 安装命令:

composer require aliziodev/payid-transactions

包简介

Payment transaction ledger and webhook event store for PayID ecosystem.

README 文档

README

Latest Version on Packagist Total Downloads PHP Version Laravel Version

Shared payment ledger package for PayID ecosystem.

Requirements

  • PHP ^8.3
  • Laravel ^12.0|^13.0 (illuminate/database, illuminate/support)

CI and Release

  • CI workflow runs on push/PR to main:
    • composer validate --strict
    • composer lint-check
    • composer test
  • Auto tag release workflow reads version from composer.json at:
    • extra.release.version
  • On push to main (when composer.json changes), the workflow:
    • creates git tag v<version> if not exists
    • creates GitHub Release with generated notes

Release steps for maintainers:

  1. Bump extra.release.version in composer.json.
  2. Merge/push to main.
  3. Workflow creates tag and GitHub release automatically.

Scope

  • Persist payment transaction lifecycle (payment_transactions).
  • Persist webhook delivery and processing trail (payment_webhook_events).
  • Provide service contract for recording and updating transaction state.

Schema Notes

  • Transaction identity is composite: provider + merchant_order_id.
  • If idempotency_key is provided, transaction upsert identity becomes provider + idempotency_key.
  • Optional polymorphic linkage is available via subject_type + subject_id.
  • Webhook table stores replay-safe event_fingerprint and processing audit fields.

Terminology Glossary

This package uses gateway-neutral naming so one schema can serve multiple providers.

  • provider: payment gateway identifier (midtrans, stripe, xendit, doku, paddle, etc).
  • merchant_order_id: merchant-side business reference for the payment intent. Common equivalents in other systems: external_id, invoice_number, order_code.
  • provider_transaction_id: gateway-side transaction/reference ID (pi_..., txn_..., etc).
  • idempotency_key: client/service generated deduplication key for retry-safe writes.
  • subject_type and subject_id: domain link (similar to polymorphic relation by convention). Examples: order, subscription, marketplace_order, wallet_topup.
  • event_fingerprint: deterministic unique value to detect webhook replay/retry.

Naming Guidelines

Recommended conventions for production teams:

  • Keep provider lowercase slug and stable (stripe, not Stripe/STRIPE).
  • Keep merchant_order_id immutable after first successful write.
  • Use idempotency_key for all external-call retries (charge, confirm, capture, etc).
  • Use consistent subject_type vocabulary across services (document in one place).
  • Put gateway-specific extras in metadata, keep core columns provider-agnostic.

Gateway Field Mapping (Practical)

  • Midtrans: merchant_order_id <= order_id, provider_transaction_id <= transaction_id.
  • Stripe: merchant_order_id <= invoice/external order reference, provider_transaction_id <= payment_intent/charge ID.
  • Xendit: merchant_order_id <= external_id, provider_transaction_id <= payment/invoice transaction ID.
  • DOKU: merchant_order_id <= merchant invoice/order number, provider_transaction_id <= DOKU transaction reference.
  • Paddle: merchant_order_id <= merchant checkout/invoice reference, provider_transaction_id <= Paddle transaction ID.

Non-scope

  • Invoice domain model.
  • Subscription orchestration.
  • Provider API adapter logic.

Install

composer require aliziodev/payid-transactions

Publish

php artisan vendor:publish --tag=payid-transactions-config
php artisan vendor:publish --tag=payid-transactions-migrations

Usage

Resolve ledger service from container:

$ledger = app(\Aliziodev\PayIdTransactions\Contracts\TransactionLedger::class);

$ledger->upsertStatus([
    'provider' => 'midtrans',
    'merchant_order_id' => 'ORDER-1001',
    'status' => 'paid',
    'amount' => 100000,
    'currency' => 'IDR',
    'subject_type' => 'subscription',
    'subject_id' => '01JABCDEF...',
]);

Prune old webhook audit rows:

php artisan payid-transactions:prune-webhooks --days=90

Real-World Scenarios

The same ledger structure can be used across local and global gateways for ecommerce, subscription billing, marketplace payouts, and digital products.

1) Midtrans - ecommerce checkout (one-time payment)

$ledger->recordChargeAttempt([
    'provider' => 'midtrans',
    'merchant_order_id' => 'ECOM-20260413-0001',
    'idempotency_key' => 'checkout-user-123-cart-888-v1',
    'status' => 'pending',
    'amount' => 350000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-01JXYZ123',
    'customer_reference' => 'user123@example.com',
    'metadata' => [
        'channel' => 'qris',
        'cart_id' => 'CART-888',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'midtrans',
    'merchant_order_id' => 'ECOM-20260413-0001',
    'provider_transaction_id' => 'trx-9f3c1',
    'status' => 'paid',
    'amount' => 350000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-01JXYZ123',
]);

2) Stripe - SaaS subscription renewal

$ledger->recordChargeAttempt([
    'provider' => 'stripe',
    'merchant_order_id' => 'INV-2026-05-ACME-01',
    'idempotency_key' => 'stripe-sub-renew-sub_01ABC-2026-05',
    'status' => 'pending',
    'amount' => 199900,
    'currency' => 'USD',
    'subject_type' => 'subscription',
    'subject_id' => 'SUB-01ABC',
    'customer_reference' => 'cus_Nx12ABC',
    'metadata' => [
        'invoice_id' => 'in_1Px...',
        'billing_cycle' => '2026-05',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'stripe',
    'merchant_order_id' => 'INV-2026-05-ACME-01',
    'provider_transaction_id' => 'pi_3Qx...',
    'status' => 'paid',
    'amount' => 199900,
    'currency' => 'USD',
    'subject_type' => 'subscription',
    'subject_id' => 'SUB-01ABC',
]);

3) Paddle - digital product/license sale

$ledger->recordChargeAttempt([
    'provider' => 'paddle',
    'merchant_order_id' => 'LIC-2026-0042',
    'idempotency_key' => 'paddle-checkout-ctm_778-prod_42',
    'status' => 'pending',
    'amount' => 4900,
    'currency' => 'USD',
    'subject_type' => 'license_order',
    'subject_id' => 'LIC-ORD-42',
    'customer_reference' => 'ctm_778',
    'metadata' => [
        'product_id' => 'pro_plan',
        'license_type' => 'lifetime',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'paddle',
    'merchant_order_id' => 'LIC-2026-0042',
    'provider_transaction_id' => 'txn_01hxyz...',
    'status' => 'paid',
    'amount' => 4900,
    'currency' => 'USD',
    'subject_type' => 'license_order',
    'subject_id' => 'LIC-ORD-42',
]);

4) DOKU - local VA payment

$ledger->recordChargeAttempt([
    'provider' => 'doku',
    'merchant_order_id' => 'DOKU-ORDER-0099',
    'idempotency_key' => 'doku-va-order-99-v1',
    'status' => 'pending',
    'amount' => 275000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-0099',
    'customer_reference' => 'customer-0099',
    'metadata' => [
        'channel' => 'va_bni',
        'store' => 'jakarta-01',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'doku',
    'merchant_order_id' => 'DOKU-ORDER-0099',
    'provider_transaction_id' => 'DOKU-TXN-7788',
    'status' => 'paid',
    'amount' => 275000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-0099',
]);

5) Xendit - online store with invoice lifecycle

$ledger->recordChargeAttempt([
    'provider' => 'xendit',
    'merchant_order_id' => 'XND-INV-2026-01',
    'idempotency_key' => 'xendit-invoice-ext_123-v1',
    'status' => 'pending',
    'amount' => 850000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-7788',
    'customer_reference' => 'customer@example.com',
    'metadata' => [
        'invoice_id' => 'inv-123',
        'payment_method' => 'ewallet',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'xendit',
    'merchant_order_id' => 'XND-INV-2026-01',
    'provider_transaction_id' => 'pay-abc-001',
    'status' => 'paid',
    'amount' => 850000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-7788',
]);

Webhook Audit Example

Use webhook event store for retries/replay visibility and processing outcomes:

$event = $ledger->recordWebhookEvent([
    'provider' => 'stripe',
    'event_fingerprint' => hash('sha256', 'stripe|evt_123|pi_123'),
    'external_event_id' => 'evt_123',
    'merchant_order_id' => 'INV-2026-05-ACME-01',
    'provider_transaction_id' => 'pi_3Qx...',
    'signature_valid' => true,
    'payload' => ['type' => 'invoice.paid'],
    'received_at' => now(),
]);

$ledger->markWebhookProcessed($event, true);

Suggested Subject Mapping

  • ecommerce order: subject_type = order, subject_id = order_id
  • subscription billing: subject_type = subscription, subject_id = subscription_id
  • marketplace order: subject_type = marketplace_order, subject_id = marketplace_order_id
  • digital goods/license: subject_type = license_order, subject_id = license_order_id
  • wallet top-up: subject_type = wallet_topup, subject_id = topup_id

统计信息

  • 总下载量: 8
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 6
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-04-13

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固