history: payments hanya run terbaru, TANGGAL pindah ke judul, MEMO dihapus (DB+UI)
This commit is contained in:
1 parent
a3251eebc4
commit
344de409cd
10 files changed
+83
-41
No files matched your search
@@ -29,7 +29,7 @@ Two tools scan the Vexanium blockchain voters table for accounts whose only vote
|
||||
- The web list shows RANK / AKUN / STAKE (VEX) / VOTE TERAKHIR columns (3 stats cells). Vote weight stays in the DB and `/api/search` JSON but is not rendered as a column.
|
||||
- Token contract is `vex.token` (NOT `eosio.token` — that name doesn't exist on Vexanium), 4-decimal VEX, chain_id `f9f432b1851b5c179d2091a96f593aaed50ec7466b74f89301f957a83e56ce1f`. Distribution signs `vex.token::transfer` with the BP `active` key.
|
||||
- Distribution (spec §V19–V27): each run pays the whole liquid balance pro-rata by stored `staked`, shares floored at 4 decimals with dust left in the account, one transfer per voter. A txid that can't be confirmed (`GET {DATABISNIS_API}/v2/history/get_transaction?id=<txid>` returns no `executed`) is never re-sent the same run — that payment stays `failed` and rejoins the next day. No-op (exit 0, no writes) when the voters table is empty or balance < 0.0001. The dashboard's `/history` view renders `distribute_runs` + `distribute_payments` read-only.
|
||||
- Dashboard layout (spec §V28): desktop gives AKUN/STAKE/VOTE equal width with AKUN left and STAKE/VOTE centered; tablet keeps the fixed STAKE column near page center; `/history` uses six-column run/payment grids; mobile turns history rows into labeled cards, including MEMO and TXID. HTML responses use `Cache-Control: no-store`; stylesheet URL is versioned with `?v=` for deploy cache-busting.
|
||||
- Dashboard layout (spec §V28): desktop gives AKUN/STAKE/VOTE equal width with AKUN left and STAKE/VOTE centered; tablet keeps the fixed STAKE column near page center; `/history` uses a six-column run grid and a four-column payment grid (AKUN/JUMLAH/STATUS/TXID) that shows only the latest run with its date in the title — no TANGGAL or MEMO column (memo is on-chain only, not stored); mobile turns history rows into labeled cards. HTML responses use `Cache-Control: no-store`; stylesheet URL is versioned with `?v=` for deploy cache-busting.
|
||||
- Liquid balance (spec §V16): a 4th stat cell "SALDO LIQUID" shows the BP account's liquid VEX (`account.core_liquid_balance`) fetched from `GET {DATABISNIS_API}/v2/state/get_account?account=<BP>`. The dashboard fetches it live but caches per-worker in memory for `DASH_LIQUID_TTL` (default 60s); a failed fetch keeps the last value (or renders `—` if none ever succeeded) and the failure is also cooled-down so the API isn't hammered. The dashboard still never writes to the DB.
|
||||
|
||||
## Layout
|
||||
@@ -39,7 +39,7 @@ Two tools scan the Vexanium blockchain voters table for accounts whose only vote
|
||||
- `db.py` — storage abstraction (sqlite default | mysql via PyMySQL); `connect/query/queryone/replace_snapshot`; `%s` → `?` for sqlite; `query` returns list. Juga tabel distribusi: `distribute_runs` + `distribute_payments` (append-only) + helper `ensure_distribute_schema/record_run/record_payment/update_payment_status/update_run_status/list_runs/list_payments`.
|
||||
- `get_voters.js` — reference implementation only.
|
||||
- `distribute.py` — pembayaran harian: fetch liquid balance → `compute_shares` (Decimal floor 4-des, sisa di akun) → sign `vex.token::transfer` via pyntelope (`trx.link` ambil ABI+TAPOS dari node, `sign` dengan `VEX_BP_PRIVATE_KEY`, `.send()`) → catat `sent/failed` per voter; verifikasi txid via Hyperion sebelum kirim ulang; `--dry-run` = rencana ⊥ tanda tangan. `test_distribute.py` — oracle (mock chain+pyntelope, temp DB).
|
||||
- `dashboard.py` + `templates/index.html` + `templates/history.html` + `static/style.css` + `static/app.js` — Flask web dashboard; reads the store via `db.py`, styled per `DESIGN.md`; `app.js` = debounced live owner search (fetch `/api/search`), degrades to the server-side `?q=` GET form if JS is off. `/history` = riwayat distribusi read-only; `run-list`/`pay-list` use six-column desktop/tablet grids and labeled mobile cards.
|
||||
- `dashboard.py` + `templates/index.html` + `templates/history.html` + `static/style.css` + `static/app.js` — Flask web dashboard; reads the store via `db.py`, styled per `DESIGN.md`; `app.js` = debounced live owner search (fetch `/api/search`), degrades to the server-side `?q=` GET form if JS is off. `/history` = riwayat distribusi read-only; `run-list` = six-column desktop/tablet grid, `pay-list` = four-column grid (AKUN/JUMLAH/STATUS/TXID) showing only the latest run with its date in the title, and labeled mobile cards.
|
||||
- `gunicorn.conf.py` — gunicorn production config (bind/workers from `config`, sync worker). `run.sh` — launcher: `./run.sh` = `./venv/bin/gunicorn -c gunicorn.conf.py dashboard:app` from any cwd.
|
||||
- `config.py` — loads env/`.env` (python-dotenv) → `TARGET_BP`, `API_NODE`, `DB_PATH`, `DB_BACKEND`, `DB_HOST`, `DB_PORT`, `DB_USER`, `DB_PASS`, `DB_NAME`, `MIN_STAKED_VEX`, `PAGE_SIZE`, `DASH_HOST`, `DASH_PORT`, `DASH_WORKERS`, `VEX_STALE_DAYS`, `DATABISNIS_API`, `DASH_LIQUID_TTL`, `BP_PRIVATE_KEY`, `DISTRIBUTE_HOUR`, `DISTRIBUTE_MAX_ATTEMPTS`; shared by get_voters & dashboard.
|
||||
- `scan_loop.py` — scheduler dalam container stack: menunggu batas `SCAN_HOURS` (lokal via `TZ`), panggil `get_voters.main()`; skan-awal `SCAN_RUN_ON_START` + tunggu DB siap; loop tak pernah keluar.
|
||||
|
||||
@@ -52,9 +52,9 @@ api: POST `https://v2.vexascan.com:2096/v1/chain/push_transaction` (signed via p
|
||||
api: POST `https://v2.vexascan.com:2096/v1/chain/get_info` → chain_id (utk signing)
|
||||
api: GET `https://api.databisnis.id/v2/history/get_transaction?id=<txid>` (Hyperion) → {executed, trx_id, lib} — guard resend
|
||||
db: table `distribute_runs` (run_id PK, run_date, balance_start, total_voters, total_staked, total_sent, status, created_at) via `db.py`; append
|
||||
db: table `distribute_payments` (payment_id PK, run_id FK, owner, amount, memo, txid, status[pending|sent|failed], error, created_at, updated_at) via `db.py`; append
|
||||
db: table `distribute_payments` (payment_id PK, run_id FK, owner, amount, txid, status[pending|sent|failed], error, created_at, updated_at) via `db.py`; append; ⊖ kolom memo (V23 hanya on-chain)
|
||||
cmd: `./venv/bin/python distribute.py` → stdout id-ID (rencana + hasil); `--dry-run` → rencana tanpa sign
|
||||
web: GET `/history` → HTML runs summary + per-voter log, read-only, gaya DESIGN.md; 6-kolom desktop/tablet, kartu berlabel mobile
|
||||
web: GET `/history` → HTML runs summary + per-voter log, read-only, gaya DESIGN.md; runs 6-kolom, payments 4-kolom (AKUN/JUMLAH/STATUS/TXID) hanya run terbaru + tanggal di judul, kartu berlabel mobile
|
||||
env: `VEX_BP_PRIVATE_KEY` (secret swarm / env dev), `DISTRIBUTE_HOUR` (default 10), `DISTRIBUTE_MAX_ATTEMPTS` — via `config.py` (`.env`)
|
||||
|
||||
## §V — Invariants
|
||||
@@ -79,12 +79,12 @@ V19: target transfer = kontrak `vex.token` (konstanta chain hardcoded; ⊥ diuba
|
||||
V20: saldo distribusi dari chain `get_currency_balance` pd `vex.token`; share = floor(balance×stake÷total_stake) 4 desimal; Σshare ≤ balance; sisa (dust) tetap di akun
|
||||
V21: ∀ transfer → dicatat di `distribute_payments` sbg `pending` SEBELUM kirim; status → `sent`|`failed` dr hasil tx; ⊥ hapus baris (append)
|
||||
V22: retry → hanya baris `failed`; baris `sent` ⊥ dikirim ulang; sebelum resend, verifikasi txid via `GET {DATABISNIS_API}/v2/history/get_transaction` → `executed` → tandai `sent` (⊥ duplikat)
|
||||
V23: memo per run = `DATABISNISID PROFIT SHARE YYYY-MM-DD` — sama utk seluruh transfer run
|
||||
V23: memo per run = `DATABISNISID PROFIT SHARE YYYY-MM-DD` — sama utk seluruh transfer run, hanya on-chain (⊖ disimpan DB)
|
||||
V24: run harian `DISTRIBUTE_HOUR` (default 10) waktu lokal `TZ`; ⊥ beku/carryover — hitung ulang tiap hari dari snapshot tersimpan
|
||||
V25: pemilih kosong | saldo < 1 unit shareable → no-op senyap, ⊥ tulis DB
|
||||
V26: `VEX_BP_PRIVATE_KEY` ⊥ pernah di-log/print; `--dry-run` utk uji lokal (⊥ sign)
|
||||
V27: dashboard read-only; `/history` baca `distribute_*` via `db.py`; ⊥ mutasi
|
||||
V28: web list desktop → kolom AKUN/STAKE/VOTE sama lebar (RANK tetap 72px); AKUN kiri; STAKE & VOTE TERAKHIR center; tablet grid lama; history runs/payments 6 kolom desktop/tablet; mobile → kartu berlabel ∀ field termasuk MEMO/TXID; HTML `no-store` + stylesheet versioned
|
||||
V28: web list desktop → kolom AKUN/STAKE/VOTE sama lebar (RANK tetap 72px); AKUN kiri; STAKE & VOTE TERAKHIR center; tablet grid lama; history → runs 6 kolom, payments 4 kolom (AKUN/JUMLAH/STATUS/TXID) hanya run terbaru (max run_id), tanggal run di judul; ⊖ MEMO (kolom DB + UI dihapus, migrasi drop kolom); mobile → kartu berlabel ∀ field; HTML `no-store` + stylesheet versioned
|
||||
|
||||
## §T — Tasks
|
||||
id|status|task|cites
|
||||
@@ -118,6 +118,7 @@ T27|x|tests: test_distribute.py (mock chain+pyntelope, temp DB: math share, memo
|
||||
T28|x|hygiene: .gitignore += `.oc/`; stage penghapusan README.md (stub kosong)|
|
||||
T29|x|dashboard layout: grid STAKE seimbang desktop/tablet; `/history` 6-kolom + kartu mobile berlabel; CSS cache-bust + HTML no-store|V28,I.web
|
||||
T30|x|dashboard desktop: kolom AKUN/STAKE/VOTE sama lebar, AKUN kiri, STAKE+VOTE center|V28,I.web
|
||||
T31|x|history payments: hanya run terbaru (max run_id) + kolom TANGGAL pindah ke judul; kolom MEMO dihapus (DB + UI, migrasi drop kolom di ensure_distribute_schema)|V27,V28,I.db,I.web
|
||||
|
||||
## §B — Bug log
|
||||
id|date|cause|fix
|
||||
|
||||
+7
-2
@@ -208,10 +208,15 @@ def api_search():
|
||||
|
||||
@app.get('/history')
|
||||
def history():
|
||||
"""V27: riwayat distribusi profit-share (read-only) — runs + per-pemilih."""
|
||||
"""V27: riwayat distribusi profit-share (read-only) — runs + per-pemilih.
|
||||
|
||||
Payments hanya run terbaru (V28); tanggal run terbaru ditampilkan di judul.
|
||||
"""
|
||||
runs = db.list_runs()
|
||||
payments = db.list_payments()
|
||||
latest = runs[0][0] if runs else None
|
||||
payments = db.list_payments(run_id=latest)
|
||||
return render_template('history.html', runs=runs, payments=payments,
|
||||
latest_date=runs[0][1] if runs else None,
|
||||
bp=TARGET_BP)
|
||||
|
||||
|
||||
|
||||
@@ -116,7 +116,6 @@ _PAY_COLS = (
|
||||
'run_id INTEGER NOT NULL, '
|
||||
'owner VARCHAR(13) NOT NULL, '
|
||||
'amount DOUBLE NOT NULL, '
|
||||
'memo TEXT NOT NULL, '
|
||||
'txid TEXT, '
|
||||
'status TEXT NOT NULL, '
|
||||
'error TEXT, '
|
||||
@@ -141,11 +140,32 @@ def ensure_distribute_schema():
|
||||
else:
|
||||
cur.execute(_RUN_DDL_MYSQL)
|
||||
cur.execute(_PAY_DDL_MYSQL)
|
||||
_drop_pay_memo(cur)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def _drop_pay_memo(cur):
|
||||
"""Migrasi: buang kolom memo lama dari distribute_payments (idempoten).
|
||||
|
||||
Kolom `memo` pernah disimpan (V23) lalu dihapus — DB produksi yang sudah
|
||||
punya kolom perlu di-alter; DB baru langsung tanpa kolom.
|
||||
"""
|
||||
if DB_BACKEND == 'sqlite':
|
||||
cur.execute(
|
||||
"SELECT name FROM pragma_table_info('distribute_payments')")
|
||||
cols = {row[0] for row in cur.fetchall()}
|
||||
else:
|
||||
cur.execute(
|
||||
"SELECT COLUMN_NAME FROM information_schema.COLUMNS "
|
||||
"WHERE TABLE_SCHEMA = DATABASE() "
|
||||
" AND TABLE_NAME = 'distribute_payments'")
|
||||
cols = {row[0] for row in cur.fetchall()}
|
||||
if 'memo' in cols:
|
||||
cur.execute(_translate('ALTER TABLE distribute_payments DROP COLUMN memo'))
|
||||
|
||||
|
||||
def record_run(run_date, balance_start, total_voters, total_staked,
|
||||
total_sent, status, created_at):
|
||||
"""Insert baris `distribute_runs`, kembalikan run_id."""
|
||||
@@ -165,7 +185,7 @@ def record_run(run_date, balance_start, total_voters, total_staked,
|
||||
conn.close()
|
||||
|
||||
|
||||
def record_payment(run_id, owner, amount, memo, status, created_at,
|
||||
def record_payment(run_id, owner, amount, status, created_at,
|
||||
txid=None, error=None):
|
||||
"""Insert baris `distribute_payments` → payment_id."""
|
||||
ensure_distribute_schema()
|
||||
@@ -174,9 +194,9 @@ def record_payment(run_id, owner, amount, memo, status, created_at,
|
||||
cur = conn.cursor()
|
||||
cur.execute(_translate(
|
||||
'INSERT INTO distribute_payments '
|
||||
'(run_id, owner, amount, memo, txid, status, error, created_at, '
|
||||
' updated_at) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)'),
|
||||
(run_id, owner, amount, memo, txid, status, error, created_at,
|
||||
'(run_id, owner, amount, txid, status, error, created_at, '
|
||||
' updated_at) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)'),
|
||||
(run_id, owner, amount, txid, status, error, created_at,
|
||||
created_at))
|
||||
conn.commit()
|
||||
return cur.lastrowid
|
||||
@@ -224,11 +244,14 @@ def list_runs():
|
||||
'FROM distribute_runs ORDER BY run_id DESC')
|
||||
|
||||
|
||||
def list_payments():
|
||||
"""Transfer per-pemilih, terbaru dulu (gabung run untuk tanggal)."""
|
||||
def list_payments(run_id=None):
|
||||
"""Transfer per-pemilih, terbaru dulu; opsional filter satu run."""
|
||||
ensure_distribute_schema()
|
||||
return query(
|
||||
'SELECT p.payment_id, p.run_id, p.owner, p.amount, p.memo, p.txid, '
|
||||
' p.status, p.error, p.created_at, p.updated_at, r.run_date '
|
||||
'FROM distribute_payments p JOIN distribute_runs r '
|
||||
' ON p.run_id = r.run_id ORDER BY p.payment_id DESC')
|
||||
sql = ('SELECT payment_id, run_id, owner, amount, txid, status, error, '
|
||||
' created_at, updated_at FROM distribute_payments')
|
||||
params = ()
|
||||
if run_id is not None:
|
||||
sql += ' WHERE run_id = %s'
|
||||
params = (run_id,)
|
||||
sql += ' ORDER BY payment_id DESC'
|
||||
return query(sql, params)
|
||||
+1
-1
@@ -160,7 +160,7 @@ def run_distribution(dry_run=False):
|
||||
0.0, 'ok', created_at)
|
||||
pending = []
|
||||
for owner, share in shares:
|
||||
pid = db.record_payment(run_id, owner, float(share), memo, 'pending',
|
||||
pid = db.record_payment(run_id, owner, float(share), 'pending',
|
||||
created_at)
|
||||
pending.append((pid, owner, share))
|
||||
|
||||
|
||||
+4
-1
@@ -193,7 +193,7 @@ button.pill {
|
||||
}
|
||||
.pay-list .list-header,
|
||||
.pay-list .list-row {
|
||||
grid-template-columns: 1fr 140px 170px 100px 1.2fr 260px;
|
||||
grid-template-columns: 1fr 170px 110px 280px;
|
||||
}
|
||||
.list-header {
|
||||
font-family: var(--font-mono);
|
||||
@@ -229,6 +229,9 @@ button.pill {
|
||||
.list-row .vote-date { text-align: center; }
|
||||
.list-header span:nth-child(3),
|
||||
.list-header span:nth-child(4) { text-align: center; }
|
||||
.pay-list .list-header span:nth-child(2),
|
||||
.pay-list .list-header span:nth-child(3) { text-align: center; }
|
||||
.pay-list .list-header span:nth-child(4) { text-align: left; }
|
||||
.txid {
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400&family=EB+Garamond:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=4) }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=5) }}">
|
||||
</head>
|
||||
<body>
|
||||
<header class="top-nav">
|
||||
@@ -59,26 +59,22 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<p class="caption">TRANSFER PER PEMILIH</p>
|
||||
<p class="caption">TRANSFER PER PEMILIH{% if latest_date %} · {{ latest_date }}{% endif %}</p>
|
||||
|
||||
<section class="spec-list pay-list">
|
||||
<div class="list-header">
|
||||
<span>AKUN</span>
|
||||
<span>TANGGAL</span>
|
||||
<span>JUMLAH</span>
|
||||
<span>STATUS</span>
|
||||
<span>MEMO</span>
|
||||
<span>TXID</span>
|
||||
</div>
|
||||
<div class="list-rows">
|
||||
{% for pay in payments %}
|
||||
<div class="list-row">
|
||||
<span class="owner">{{ pay[2] }}</span>
|
||||
<span class="vote-date" data-label="TANGGAL">{{ pay[10] }}</span>
|
||||
<span class="stake" data-label="JUMLAH">{{ pay[3]|vex }}</span>
|
||||
<span class="vote-date" data-label="STATUS">{{ pay[6]|upper }}</span>
|
||||
<span class="txid memo" data-label="MEMO">{{ pay[4] }}</span>
|
||||
<span class="owner txid" data-label="TXID">{{ pay[5] or '—' }}</span>
|
||||
<span class="vote-date" data-label="STATUS">{{ pay[5]|upper }}</span>
|
||||
<span class="owner txid" data-label="TXID">{{ pay[4] or '—' }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty">BELUM ADA TRANSFER</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400&family=EB+Garamond:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=4) }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', v=5) }}">
|
||||
</head>
|
||||
<body>
|
||||
<header class="top-nav">
|
||||
|
||||
+12
-3
@@ -55,12 +55,17 @@ def main():
|
||||
dashboard._get_liquid_vex = lambda: 50691.4676 # suite utama ⊥ jaringan nyata
|
||||
|
||||
# ————— V27: seed riwayat distribusi utk uji /history —————
|
||||
# run lama di-seed duluan agar run_id-nya lebih kecil (⊥ run terbaru).
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')
|
||||
dbm.ensure_distribute_schema()
|
||||
old_rid = dbm.record_run(yesterday, 50000.0, 1, 1000.0, 80.0, 'ok',
|
||||
'2026-08-04T10:00:00')
|
||||
dbm.record_payment(old_rid, 'oldacct', 40.0, 'sent',
|
||||
'2026-08-04T10:00:01', txid='txold999')
|
||||
rid = dbm.record_run(today, 52186.0417, 1, 1200.0, 100.0, 'ok',
|
||||
'2026-08-05T10:00:00')
|
||||
dbm.record_payment(rid, 'acct001', 50.0,
|
||||
f'DATABISNISID PROFIT SHARE {today}', 'sent',
|
||||
dbm.record_payment(rid, 'acct001', 50.0, 'sent',
|
||||
'2026-08-05T10:00:01', txid='txabc123')
|
||||
|
||||
client = dashboard.app.test_client()
|
||||
@@ -104,9 +109,13 @@ def main():
|
||||
html = resp.get_data(as_text=True)
|
||||
check('V27 judul RIWAYAT DISTRIBUSI', 'RIWAYAT DISTRIBUSI' in html)
|
||||
check('V27 run date tampil', today in html)
|
||||
check('V27 tanggal di judul TRANSFER PER PEMILIH',
|
||||
f'TRANSFER PER PEMILIH · {today}' in html)
|
||||
check('V27 transfer per-pemilih tampil', 'acct001' in html)
|
||||
check('V27 hanya run terbaru (transfer lama tak tampil)',
|
||||
'oldacct' not in html)
|
||||
check('V27 status SENT tampil', 'SENT' in html)
|
||||
check('V27 memo tercatat', f'DATABISNISID PROFIT SHARE {today}' in html)
|
||||
check('V27 memo tak dirender', f'DATABISNISID PROFIT SHARE {today}' not in html)
|
||||
check('V27 txid tercatat', 'txabc123' in html)
|
||||
|
||||
# ————— V11: search server-side ?q= (substring, case-insensitive) —————
|
||||
|
||||
+12
-7
@@ -150,9 +150,9 @@ def main():
|
||||
calls['runs'].append((run_date, status))
|
||||
return 7
|
||||
|
||||
def fake_record_payment(run_id, owner, amount, memo, status, created,
|
||||
def fake_record_payment(run_id, owner, amount, status, created,
|
||||
txid=None, error=None):
|
||||
calls['pays'].append((owner, amount, memo, status))
|
||||
calls['pays'].append((owner, amount, status))
|
||||
return len(calls['pays'])
|
||||
|
||||
def fake_update(pid, status, txid=None, error=None, updated_at=None):
|
||||
@@ -165,7 +165,13 @@ def main():
|
||||
db.record_payment = fake_record_payment
|
||||
db.update_payment_status = fake_update
|
||||
db.update_run_status = fake_run_update
|
||||
dist.build_signed_transfer = lambda to, amount, memo: FakeSigned('tx' + to)
|
||||
signed = []
|
||||
|
||||
def fake_sign(to, amount, memo):
|
||||
signed.append(memo)
|
||||
return FakeSigned('tx' + to)
|
||||
|
||||
dist.build_signed_transfer = fake_sign
|
||||
buf = io.StringIO()
|
||||
with redirect_stdout(buf):
|
||||
rc = dist.run_distribution(dry_run=False)
|
||||
@@ -173,11 +179,10 @@ def main():
|
||||
check('V21 run tercatat (run_date)', calls['runs'][0][0]
|
||||
== datetime.now().strftime('%Y-%m-%d'))
|
||||
check('V21 2 payment pending tercatat',
|
||||
len([p for p in calls['pays'] if p[3] == 'pending']) == 2)
|
||||
len([p for p in calls['pays'] if p[2] == 'pending']) == 2)
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
check('V23 memo per run',
|
||||
all(p[2] == f'DATABISNISID PROFIT SHARE {today}'
|
||||
for p in calls['pays']))
|
||||
check('V23 memo on-chain per run',
|
||||
all(m == f'DATABISNISID PROFIT SHARE {today}' for m in signed))
|
||||
check('V21 semua sent + txid',
|
||||
all(u[1] == 'sent' and u[2].startswith('tx') for u in calls['updates']))
|
||||
check('V24 status run ok + total_sent',
|
||||
|
||||
Reference in new issue
Block a user