D
Engineering

Transfer Balance Schema

"Skema tabel order_transfer_balances, order_transfer_balance_details (dazo-whitelist) dan transfer_balances, transfer_balance_details (dazo-whitelist-api). Status lifecycle: pending/processing/completed/failed. Transfer multi-source ke satu tujuan.

Skema entitas Transfer Balance — memindahkan sisa saldo spend cap antar akun iklan member secara atomik. Data ada di dua database: dazo-whitelist (order domain) & dazo-whitelist-api (eksekusi Meta).

Arsitektur dua tabel

text
dazo-whitelist (web)                    dazo-whitelist-api (engine)
─────────────────────────               ─────────────────────────────
order_transfer_balances                 transfer_balances
  └── order_transfer_balance_details     └── transfer_balance_details
      (source accounts)                     (source accounts)

Web app mencatat order transfer; API engine mengeksekusi transfer riil ke Meta. Keduanya sinkron via endpoint /api/transfer-balance.

order_transfer_balances (dazo-whitelist)

Model: TransferBalance — URL class tidak sama dengan tabel API engine.

FieldTipeCatatan
idUUID (PK)
order_idUUID (FK)→ orders.id
destination_ads_account_idUUID (FK)Akun iklan tujuan
destination_balancedecimal:2Saldo tujuan sebelum transfer
total_transferreddecimal:2Total yang berhasil ditransfer
statusstringpending / processing / completed / failed
error_messagetext (nullable)Isi saat failed
processed_atdatetimeWaktu mulai proses
completed_atdatetimeWaktu selesai
created_by, updated_by, timestamps—Standar

Konstanta status

php
const STATUS_PENDING   = 'pending';
const STATUS_PROCESSING = 'processing';
const STATUS_COMPLETED = 'completed';
const STATUS_FAILED    = 'failed';

Method mutation

MethodFungsi
markAsProcessing()Status → processing, set processed_at
markAsCompleted($totalTransferred)Status → completed, set total_transferred & completed_at
markAsFailed($errorMessage = null)Status → failed, set error_message & completed_at

Scope

ScopeFungsi
scopePending()where('status', 'pending')
scopeProcessing()where('status', 'processing')

Relasi

MethodTipeTarget
details()HasManyOrderTransferBalanceDetail
order()BelongsToOrder
destinationAccount()BelongsToAdsAccount

order_transfer_balance_details (dazo-whitelist)

Item per akun sumber — satu transfer bisa memindahkan dari multiple akun sumber ke satu tujuan.

FieldTipe
idUUID (PK)
order_transfer_balance_idUUID (FK)
source_ads_account_idUUID (FK)
amountdecimal:2
statusstring
error_messagetext (nullable)
timestamps—

transfer_balances (dazo-whitelist-api)

Mirror eksekusi di engine.

FieldTipeCatatan
idUUID (PK)
order_idUUID (FK)Reference ke order di web app
destination_ads_account_idUUID (FK)
total_transferreddecimal:2
statusstringSama: pending/processing/completed/failed
error_messagetext (nullable)
processed_at / completed_atdatetime
timestamps—

transfer_balance_details (dazo-whitelist-api)

Item sumber di engine.

FieldTipe
idUUID (PK)
transfer_balance_idUUID (FK)
source_ads_account_idUUID (FK)
amountdecimal:2
statusstring
api_responsearray (JSON, nullable) — Response Meta Graph per-item
timestamps—

Alur eksekusi (atomic)

text
1. User submit       ── order_transfer_balances: status=pending
2. Admin approve     ── POST /api/transfer-balance (web → engine)
3. Engine proses     ── transfer_balances: status=processing
4. Per sumber        ── markAsProcessing() → push TransferBalanceJob
   a. Cek saldo riil akun sumber (GET /api/account/balance)
   b. Withdraw dari sumber (POST /api/account/withdraw)
   c. Topup ke tujuan   (POST /api/account/topup)
   d. Record detail per-item
5. Sukses            ── markAsCompleted($total) — status=completed
6. Gagal             ── markAsFailed($error) — status=failed + rollback

Alur rollback

Bila salah satu sumber gagal:

  • Item yang sudah berhasil tidak di-rollback per-item secara otomatis di model TransferBalance
  • markAsFailed($errorMessage) menandai keseluruhan transfer failed
  • Detail items menyimpan api_response untuk audit manual

Validasi saldo riil

Sebelum transfer, engine mengecek saldo riil akun sumber di Facebook via GET /api/account/balance — mencegah transfer melebihi saldo spend cap aktual.

Gambaran kasus multi-source

plaintext
Akun A (sumber 1) ──┐
Akun B (sumber 2) ──┼──► Akun Tujuan
Akun C (sumber 3) ──┘

order_transfer_balances / transfer_balances = header (tujuan, total, status) order_transfer_balance_details / transfer_balance_details = 3 baris sumber.

Endpoint terkait (API engine)

MethodEndpointFungsi
POST/api/transfer-balanceEksekusi transfer baru
GET/api/transfer-balanceRiwayat transfer
GET/api/transfer-balance/{id}Detail transfer
POST/api/transfer-balance/{id}/processProses transfer tersimpan
POST/api/account/balanceCek saldo riil akun

Langkah berikutnya