Generic CLI for eac.zigbang.in (E-Accounting / UniDocu).
Drives the UniDocu named-service API directly over HTTP. No headless browser at runtime β auth is just the JSESSIONID cookie pulled out of your local Chrome profile.
The CLI intentionally stays domain-agnostic: it only knows about EAC data and verbs. Company-/personal-specific policy (e.g. "μκΈ°κ΄λ¦¬λΉ νκΈμ μμμ¦ Γ 70%") belongs in your own shell scripts or runbooks.
npm install -g @zigbang-smarthome/eac-cli
brew install zigbang-smarthome/tap/eac-cli
curl -fsSL https://github.com/zigbang-smarthome/eac-cli/releases/latest/download/install.sh | shBefore first use: open Chrome and log in to https://eac.zigbang.in at least once so the session cookie lands in your Chrome cookie store. The CLI reads that cookie each run.
-
EAC uses Google SSO + MS Azure AD SAML β login itself can't be automated. The CLI piggybacks on your normal Chrome session.
-
Each run,
eaccopies Chrome's cookie DB to tmpdir, decrypts theJSESSIONIDfor*.zigbang.in(AES-128-CBC, key from"Chrome Safe Storage"Keychain), and pings EAC to confirm the session is alive. -
If the session is missing or expired, the CLI opens Chrome at
https://eac.zigbang.in/unidocu/view.doand prompts:- Finish the Google SSO login in Chrome.
- Quit Chrome (Cmd+Q) so the new
JSESSIONIDis flushed to disk. Chrome's cookie monster keeps cookies in memory and writes to the SQLite store on a delayed batch schedule β without an explicit quit the CLI may keep reading a stale value. - Return to the terminal and hit Enter β the CLI re-reads the fresh cookie and continues.
- Reopen Chrome normally afterwards.
Tip: turn on Chrome β Settings β On startup β "Continue where you left off" so the session cookie survives the Cmd+Q cycle. EAC re-login becomes infrequent (only when the SAP-side session truly expires).
-
macOS may prompt for Keychain access the first time (click Always Allow).
-
Override: set
EAC_JSESSIONID=<value>to bypass the keychain entirely and use a cookie sourced elsewhere (e.g. extracted from Playwright/CDP-controlled Chrome). Useful when EAC is open in a non-default Chrome profile or in CI scripts. -
Non-TTY environments (CI, piped scripts) error out instead of prompting β pass
EAC_JSESSIONIDexplicitly there.
Before the commands it helps to see the data model the CLI talks to. UniDocu has two related document spaces and two separate attachment layers.
| κ³΅κ° | μλ³μ | UI λ©λ΄ | Backend service prefix |
|---|---|---|---|
| μ ν (FI) | BELNR (SAP λ¬Έμλ²νΈ) |
λΉμ©μ μ° βΊ κ°μΈλΉμ© βΊ EAμ νκ²°μ¬ (UD_0302_000) |
ZUNIEFI_* |
| κ²°μ¬λ¬Έμ (WF) | GRONO (κ·Έλ£Ήλ²νΈ) + WF_KEY |
κ²°μ¬ν¨ (UFL_0401_020 λ±) |
ZUNIEWF_* |
νλμ μ ν(BELNR)μ κ²°μ¬μμ²μ κ±Έλ©΄ κ²°μ¬λ¬Έμ(GRONO)κ° μμ½λΌ μ νμ λΆλλ€. κ΄κ³λ 1:1.
κ°μ μμμ¦ PDFλ₯Ό μ¬λ¦¬λλΌλ μ΄λ λ μ΄μ΄μ λΆμ΄λλκ° κ²°μ¬μ UXλ₯Ό κ°λ₯Έλ€.
- μ ν λ μ΄μ΄ (
voucher attach) βZUNIEFI_4006μ μ₯ μ ν¨κ» μ°κ²°λ¨. μΈλ¬΄/νκ³νμ΄ μ ν μμΈλ·°μμ νμΈ. - κ²°μ¬λ¬Έμ λ μ΄μ΄ (
approval attach) βApprovalStepbodyμEVI_SEQνλλ‘ μ λ¬λ¨. μ΄κ² μμ΄μΌ κ²°μ¬ν¨ 리μ€νΈμμπμμ΄μ½μ΄ λ¬λ€ (WF_ATTACH_FLAG = X). μμΌλ©΄ κ²°μ¬μ μ μ₯μμ "μ²¨λΆ μλ λ¬Έμ"λ‘ λ³΄μ.
voucher create λ 1λ² λ μ΄μ΄μ, voucher request-approval μ 2λ² λ μ΄μ΄μ κ°κ° μ¬λ¦°λ€. λ λͺ
λ Ή λͺ¨λ --attach-dirλ₯Ό λ°μ κ°μ μμμ¦ ν΄λλ₯Ό λ λ² μ¬λ¦Ό. (κ°μ νμΌμ μ€λ³΅ μ
λ‘λλ μλ² μ μ₯μμ λ³κ° κΈ°λ‘μΌλ‘ λ¨λλ€.)
ZUNIEFI_4003β κΈ°λ³Έκ° κ³μ° (ZFBDT λ±)ZUNIECM_5030β μ ν λ μ΄μ΄ EVI_SEQ μ±λ²fineuploader/request.doβ μ ν λ μ΄μ΄μ νμΌ μ λ‘λZUNIEFI_4006β λΉμ©νλͺ© μ μ₯ (EVI_SEQ μ°κ²°)ZUNIEFI_5000β SAP posting β BELNR λ°κΈZUNIEFI_4203β GRONO μμ½ (μμ§ μμ μλ)ZUNIECM_5030β κ²°μ¬ λ μ΄μ΄ EVI_SEQ μ±λ²fineuploader/request.doβ κ²°μ¬ λ μ΄μ΄μ νμΌ μ λ‘λZUNIEWF_2200β κ°μΈκ²°μ¬μ λͺ©λ‘ μ‘°νZUNIEWF_4101β κ²°μ¬μ 리μ€νΈ μ‘°νApprovalStep(targetNamedServiceIdZUNIEWF_4201) β μ΅μ’ μμ
15 = 11 = voucher create, 6voucher request-approval.
eac
βββ voucher μ ν (FI, ZUNIEFI_*)
β βββ list ZUNIEFI_4200
β βββ show <BELNR|GRONO> ZUNIEFI_4207
β βββ create μ ν μμ± (Steps 1-5 β BELNR)
β βββ request-approval <BELNR> κ²°μ¬μμ² (Steps 6-11 β GRONO + μμ )
β βββ cancel-group <GRONO> κ·Έλ£Ήλ²νΈμ·¨μ (ZUNIEFI_4202)
β βββ delete <BELNR> μμμ νμμ (ZUNIEFI_4103)
β βββ attach new|upload|list μ ν λ μ΄μ΄ EVI_SEQ primitive
βββ corpcard λ²μΈμΉ΄λ(곡μ©) β μΉ΄λμ¬ κ±°λ β μμμ ν
β βββ list ZUNIEFI_1000 (λ―Έμ μ° κ±°λ)
β βββ create <CRD_SEQ> ZUNIEFI_4006 + ZUNIEFI_1009 β BELNR
βββ approval κ²°μ¬λ¬Έμ (WF, ZUNIEWF_*)
β βββ list [--box] ZUNIEWF_4500 (κ²°μ¬ν¨)
β βββ recall <GRONO> νμ (ApprovalStep + ZUNIEWF_4320)
β βββ attach new|upload|list κ²°μ¬ λ μ΄μ΄ EVI_SEQ primitive
β βββ line
β βββ list ZUNIEWF_2200 (κ°μΈκ²°μ¬μ λͺ©λ‘)
β βββ show <SEQ> [--json] ZUNIEWF_2203 (κ²°μ¬μ + κ²°μ¬μ)
β βββ approvers <SEQ> --grono <G> ZUNIEWF_4101 (νΉμ GRONOμ©)
β βββ save <SEQ> <approvers.json> ZUNIEWF_2201 (κ²°μ¬μ ν΅μ§Έ μ μ₯)
β βββ add <SEQ> <user> [--at lev] μ¬μ©μ μΆκ° (read β splice β save)
β βββ remove <SEQ> <level|wf_id> κ²°μ¬μ μ κ±° (read β splice β save)
β βββ search-user <name> ZUNIEWF_1035 (μ΄λ¦μΌλ‘ EAC μ¬μ©μ κ²μ)
βββ call <id> --prog [--data] raw named-service escape hatch
βββ config show|init ~/.config/eac/config.json
voucher list β ZUNIEFI_4200. κΈ°λ³Έμ νμ¬ μ, BSTAT=V (μμμ ν). --bstat *λ‘ μ 체, --statsλ‘ λ―Έμμ /μ§νμ€/μΉμΈ/νμ/λ°λ € νν°.
voucher show <BELNR|GRONO> β ZUNIEFI_4207. BELNR/GRONO μ무 κ±°λ λ°μ μμΈ νμ (BELNRμ μλ² 3-κ°μ μ‘°ν μλμ° λ΄μμ μλ resolve).
voucher create β μ ν μμ±. Steps 1-5. BELNR λ°ν. μμ§ GRONO μμ (κ²°μ¬ μ ).
--item <name> Preset name from config.items (e.g. "μκΈ°κ΄λ¦¬λΉ")
--title <text> μ ν μ λͺ© (SGTXT)
--bldat <YYYYMMDD> μμμ¦ λ μ§
--budat <YYYYMMDD> μ κΈ°μΌμ (default: today)
--amount <won> κΈμ‘ (μ μ)
--attach-dir <path> μ²¨λΆ ν΄λ (optional)
voucher request-approval <BELNR> β κ²°μ¬μμ². Steps 6-11. GRONO λ°κΈ + μ€μ μμ . --attach-dir νμ (κ²°μ¬ λ μ΄μ΄ 첨λΆ).
voucher cancel-group <GRONO> β κ·Έλ£Ήλ²νΈμ·¨μ (ZUNIEFI_4202). νμ(STATS=C) λλ λ°λ €(STATS=R)λ μ νμ λΆμ GRONOλ₯Ό νμ΄μ€λ€. νλ¦° BELNRμ λ€μ κ²°μ¬μμ² κ°λ₯ (μμ μ¬νμ΄ μμΌλ©΄ request-approvalλ‘ λ°λ‘ μ¬μμ , HKONT/μ μ λ± μμ ν΄μΌ νλ€λ©΄ delete ν μλ‘ create).
voucher delete <BELNR> β μμμ νμμ (ZUNIEFI_4103). GRONOκ° λΉμ΄μλ(λ―Έμμ ) μμμ νλ₯Ό μμ μμ νλ€. λ²μΈμΉ΄λ μ μ° κ±΄μ΄λΌλ©΄ μλμ μΉ΄λ κ±°λ(CRD_SEQ)κ° λ―Έμ μ° νλ‘ λμμ corpcard list/corpcard createλ‘ λ€μ μ‘μ μ μλ€. GRONOκ° λΆμ΄μμΌλ©΄ λ¨Όμ cancel-groupμ κ±°μ³μΌ νλ€.
voucher attach {new, upload, list} β μ ν λ μ΄μ΄ EVI_SEQ μ§μ μ‘°μ (λ³΄ν΅ createκ° μλ μ²λ¦¬νλ―λ‘ μΈ μΌ λ§μ§ μμ).
λ²μΈμΉ΄λ(곡μ©) μ¬μ©λ΄μμ μΉ΄λμ¬ λ°μ΄ν° κΈ°λ°μΌλ‘ μμμ νννλ€. μκΈ°κ΄λ¦¬λΉ/μΌλ°κ²½λΉμ λ¬λ¦¬ μμμ¦μ μ§μ 첨λΆνμ§ μλλ€ (μΉ΄λμ¬κ° SAP νλ¨μ κ±°λ λ°μ΄ν°λ‘ μλ 첨λΆ).
corpcard list [--from] [--to] [--merch] β λ―Έμ μ° μΉ΄λ κ±°λ λͺ©λ‘ (ZUNIEFI_1000). μ΄λ―Έ μ ννλ κ±°λλ λΉ μ§λ€. κ° νμ΄ CRD_SEQλ‘ μλ³λ¨.
corpcard create <CRD_SEQ> --hkont --remark [--budat] [--bldat] β μΉ΄λ κ±°λλ₯Ό μμμ νλ‘ λ³ν (ZUNIEFI_4006 + ZUNIEFI_1009 β BELNR). μ²¨λΆ EVI_SEQ νΈμΆ μμ.
--hkont <code> G/L κ³μ (μ: 52010102 νμλ / 52060101 νμλΉ / 52050104 μ λλΉ-μ μ©μΉ΄λ / 52030203 μλ΄κ΅ν΅λΉ)
--hkont-text <name> νκΈ°μ© (μ΅μ
)
--remark <text> μ μ. νμ: [λ²μΈμΉ΄λ/κ±°λμ²/μ°Έμμ] λλ [λ²μΈμΉ΄λ/μΆλ°βλμ°©]
--budat <YYYYMMDD> μ κΈ°μΌ (default: today; κ²°μ μ λ§κ° νμ μ΅μ 1μΌ κ°μ )
--bldat <YYYYMMDD> μ¦λΉμΌ (default: μΉ΄λ μΉμΈμΌ)
λ°κΈλ BELNRμ κ·Έλλ‘ eac voucher request-approval <BELNR> --item λ²μΈμΉ΄λ --title "..."λ‘ κ²°μ¬μμ². κ²°μ¬μ μ [κ°μΈ]-μΌλ°κ²½λΉ κ·Έλλ‘ (μ±λ―Όμ§ β Leah Song).
μ°Έκ³ : λ²μΈμΉ΄λλ νμ¬ μ μ± μ λΆκ°μΈ V3 (λΆκ³΅μ λ§€μ μΈμ‘)μ κ°μ λ‘ μ μ©. EVIKB=FI_12 (λ²μΈμΉ΄λκΈ°λͺ μ). MWSKZ/EVIKBλ μ½λμμ μλ μΈν .
approval list [--box progress|approved|rejected|pending] β ZUNIEWF_4500. π νμλ‘ κ²°μ¬ λ μ΄μ΄ μ²¨λΆ μ 무 νλμ 보μ.
approval recall <GRONO> β μ§νμ€ κ²°μ¬λ¬Έμ νμ. λ΄λΆλ ApprovalStep + targetNamedServiceId=ZUNIEWF_4320 + APPR_STAT=E.
approval attach {new, upload, list} β κ²°μ¬ λ μ΄μ΄ EVI_SEQ μ§μ μ‘°μ (λ³΄ν΅ request-approvalμ΄ μλ μ²λ¦¬).
approval line list β κ°μΈκ²°μ¬μ λͺ©λ‘ (ZUNIEWF_2200).
approval line show <SEQ> β κ²°μ¬μ μ κ²°μ¬μλ₯Ό κ·Έ μμ²΄λ‘ μ‘°ν (ZUNIEWF_2203). --jsonμ λΆμ΄λ©΄ raw λ°°μ΄μ μΆλ ₯ β κ·Έλλ‘ line save μ
λ ₯μΌλ‘ μ¬μ© κ°λ₯.
approval line approvers <SEQ> --grono <G> β νΉμ κ²°μ¬λ¬Έμ(GRONO)μ λ¬ΆμΈ κ²°μ¬μ νκ° κ²°κ³Ό (ZUNIEWF_4101). κ²°μ¬μ μ체보λ€λ κ·Έ λ¬Έμκ° μ§μ§ λꡬλ₯Ό κ±°μΉλκ°λ₯Ό λ³Έλ€.
approval line save <SEQ> <approvers.json> β κ²°μ¬μ 리μ€νΈ ν΅μ§Έ μ μ₯ (ZUNIEWF_2201). νμΌμ line show --json μΆλ ₯ νμ.
approval line add <SEQ> <name|wf_id> [--at lev] β κ²°μ¬μ μ μ¬μ©μ ν λͺ
μΆκ°. <name>μ΄λ©΄ ZUNIEWF_1035λ‘ κ²μν΄ λ¨μΌ λ§€μΉμΌ λλ§ μ§ν. --atμ 1-based μμΉ (μμΌλ©΄ λμ μΆκ°). λ΄λΆμ μΌλ‘ show β splice β save.
approval line remove <SEQ> <level|wf_id> β κ²°μ¬μ μμ ν λͺ
μ κ±°. μ«μλ©΄ 1-based level, μλλ©΄ WF_ID (μ: ZB01010)λ‘ λ§€μΉ.
approval line search-user <name> β EAC μ¬μ©μ κ²μ (ZUNIEWF_1035). νκΈ/μλ¬Έ λ¨νΈ λͺ¨λ κ°λ₯.
κ²°μ¬μ μμ±/μμ μ체λ μμ§ μλν μ λ¨ (μλ UIμμ ν λ²λ μΊ‘μ³ μ μ‘ν). μ λΌμΈμ΄ νμνλ©΄ EAC UIμμ μμ±ν λ€
add/remove/saveλ‘ κ²°μ¬μλ§ μλν.
Wrapping μλ μλΉμ€ μ§μ νΈμΆμ© escape hatch.
eac call ZUNIEFI_4207 --prog DRAFT_0010 --data '{"GRONO":"FI20260000023922"}'config showβ νμ¬ config JSON νλ¦°νΈconfig initβ~/.config/eac/config.jsonμμΌλ©΄ κΈ°λ³Έκ° μμ±
eac-cliλ "μ ν μμ± + κ²°μ¬μμ² ν λ²μ"λΌλ compositeλ₯Ό μΌλΆλ¬ μ 곡νμ§ μλλ€. μ€κ°μ μ€ν¨νλ©΄ μν(BELNR λ°κΈλλλ° GRONO μμ)κ° μ¨κ²¨μ Έ λ³΅κ΅¬κ° μ΄λ €μμ§κΈ° λλ¬Έ. νμνλ©΄ shell scriptλ‘ 2 λ¨κ³λ₯Ό λͺ μμ μΌλ‘ μ‘°ν©.
# Step 1: μ ν μμ±
BELNR=$(eac voucher create \
--item "μκΈ°κ΄λ¦¬λΉ" \
--title "2026λ
5μ μκΈ°κ΄λ¦¬λΉ" \
--bldat 20260503 \
--amount 30800 \
--attach-dir ./μκΈ°κ΄λ¦¬λΉ/202605 \
| awk '/^BELNR/ {print $2}')
echo "BELNR=$BELNR"
# Step 2: κ²°μ¬μμ²
eac voucher request-approval "$BELNR" \
--item "μκΈ°κ΄λ¦¬λΉ" \
--title "2026λ
5μ μκΈ°κ΄λ¦¬λΉ" \
--attach-dir ./μκΈ°κ΄λ¦¬λΉ/202605μ΄κ±Έ κ·Έλλ‘ μλ³ task scriptλ‘ κ°μΈμ ~/bin/ λλ repoμ scripts/μ λλ©΄ λ¨:
#!/usr/bin/env bash
# scripts/μκΈ°κ΄λ¦¬λΉ-μμ .sh
set -euo pipefail
month="$1"; bldat="$2"; receipt="$3"
y="${month:0:4}"; m=$((10#${month:4:2}))
title="${y}λ
${m}μ μκΈ°κ΄λ¦¬λΉ"
amount=$(( receipt * 7 / 10 ))
dir="./μκΈ°κ΄λ¦¬λΉ/${month}"
BELNR=$(eac voucher create --item "μκΈ°κ΄λ¦¬λΉ" --title "$title" \
--bldat "$bldat" --amount "$amount" --attach-dir "$dir" \
| awk '/^BELNR/ {print $2}')
eac voucher request-approval "$BELNR" --item "μκΈ°κ΄λ¦¬λΉ" \
--title "$title" --attach-dir "$dir"# μ: 23922 μμ νλλ° μμμ¦ μλͺ» λ£μμ
eac approval recall FI20260000023922
eac voucher cancel-group FI20260000023922
# μ΄μ BELNR 3200005520 μ "λ―Έμμ " μν. λ€μ κ²°μ¬μμ² κ°λ₯:
eac voucher request-approval 3200005520 \
--item "μκΈ°κ΄λ¦¬λΉ" \
--title "2026λ
5μ μκΈ°κ΄λ¦¬λΉ (μμ )" \
--attach-dir ./μκΈ°κ΄λ¦¬λΉ/202605μ ν(BELNR)λ HKONT/EVIKB νμ ν SAPμ postingλλ―λ‘ itemμ λ°κΎΈλ €λ©΄ μ μ ν νμ. κΈ°μ‘΄ κ²μ νμ β κ·Έλ£Ήλ²νΈμ·¨μ β μμμ νμμ ν μλ‘ create:
# μλͺ»λ item
eac approval recall FI20260000023877
eac voucher cancel-group FI20260000023877
eac voucher delete 3200005641 # μμμ ν μμ μμ
# μ¬λ°λ₯Έ item μΌλ‘ μλ‘ μμ
BELNR=$(eac voucher create --item "μκΈ°κ΄λ¦¬λΉ" ...)
eac voucher request-approval "$BELNR" --item "μκΈ°κ΄λ¦¬λΉ" ...νμλ(52010102) μ νμλΉ(52060101) μ²λΌ μλͺ» λΆλ₯νλ€κ° νκ³ν λ°λ €λ₯Ό λ°μμ λ. μΉ΄λ κ±°λ(CRD_SEQ)λ μ΄λ¦¬κ³ HKONT/μ μλ§ λ€μ μ‘μΌλ©΄ λλ€.
# 1) λ°λ € κ²°μ¬λ¬Έμμ GRONO νμ΄λ΄κΈ°
eac voucher cancel-group FI20260000023988 # GRONO κ° λΆμ΄μλ νμ/λ°λ € μ ν detach
# 2) μμμ ν μ체λ₯Ό μμ β CRD_SEQ κ° λ―Έμ μ° νλ‘ λ³΅κ·
eac voucher delete 3200005642
# 3) μΉ΄λ κ±°λ λ€μ μ‘κΈ° (CRD_SEQ κ·Έλλ‘ β list λ‘ νμΈ)
eac corpcard list --merch μ΄λ§νΈ24
BELNR=$(eac corpcard create 20260421001000020116 \
--hkont 52010102 \
--hkont-text "ν)볡리νμλΉ-νμλ" \
--remark "[λ²μΈμΉ΄λ/μ΄λ§νΈ24μ²λ΄λ¦¬ν
μΌμ /λ°μκ±Έ, μ€νμ]")
# 4) κ²°μ¬μμ²
eac voucher request-approval "$BELNR" --item λ²μΈμΉ΄λ --title "[λ²μΈμΉ΄λ/...]"π‘ νκ³ν λ£°: μ°Έμμκ° μ μ μ§μμ΄λ©΄ νμλ(
52010102), μΈλΆμΈ 1λͺ μ΄μ + μ¬μ νμ κΈ°μμκ° μμ΄μΌλ§ νμλΉ(52060101).
eac voucher list # λ΄ μμμ ν
eac voucher list --bstat '*' --stats '*' # μ 체
eac voucher show FI20260000023922
eac approval list # μ§νμ€
eac approval list --box rejected # λ°λ €/νμ
# κ²°μ¬μ ꡬ쑰 νμΈ
eac approval line list
eac approval line approvers 0000000002 --grono FI20260000023922~/.config/eac/config.json. ν λ² μ€μ νκ³ --item <name> μΌλ‘ μ¬μ¬μ©.
{
"user": {
"pernr": "ZB01135",
"bukrs": "K001",
"pernrName": "λ°μκ±Έ",
"wfIdText": "YG Park (λ°μκ±Έ)",
"kostl": "226020",
"kostlText": "Device Engineering",
"wfDept": "0000252100",
"wfDeptText": "Service Engineering"
},
"items": {
"μκΈ°κ΄λ¦¬λΉ": {
"hkont": "52010108",
"hkontText": "ν)볡리νμλΉ-μκΈ°κ΄λ¦¬λΉ",
"evikb": "FI_21",
"evikbText": "μ₯λ €μ§μκΈ",
"wfLineSeq": "0000000002",
"wfLineLin1": "0000000816"
}
}
}μ item μΆκ° μ νμν κ°:
hkontβ G/L κ³μ (e.g.52010177ν)볡리νμλΉ-κΈ°ν)evikbβ μ ν μ’ λ₯ μ½λ (e.g.FI_21μ₯λ €μ§μκΈ,FI_22μΌλ°κ²½λΉ)wfLineSeq/wfLineLin1β ν΄λΉ itemμ κ°μΈκ²°μ¬μ (μ°Έκ³ :eac approval line listλ‘ νμΈ)
Preset keyλ νκΈ μ΄λ¦(μκΈ°κ΄λ¦¬λΉ, κ°μ‘±μμ¬λΉ, μ격근무μ§μλΉ, β¦) μ¬μ© κΆμ₯.
bun install
bun run src/index.ts --helpRelease: gh workflow run release.yml β oneupκ° version bump + npm/Homebrew publish μλν.
MIT