⚙️
Xpensio — SAP Entegrasyon Teknik Kılavuzu
ECC 6.0 · S/4HANA On-Premise · S/4HANA Cloud · SuccessFactors
Versiyon 2.0 · Mart 2026 · Gizlilik: Müşteri Teknik Dokümanı
📑 İçindekiler
5 S/4HANA Cloud + SuccessFactors
5b Kart Mutabakatı & UMSKZ (Yeni)
6 Güvenlik & Ağ Gereksinimleri
1 Genel Mimari
1.1 Adapter Kalıbı (Factory Pattern)
Xpensio, tüm ERP/HR entegrasyonlarını Adapter Factory kalıbıyla yönetir. Ortam değişkenine (SAP_TYPE, IDENTITY_PROVIDER) göre uygun adapter otomatik seçilir:
┌─────────────────────── Xpensio Backend (NestJS) ───────────────────────┐
│ │
│ SapAdapterFactory IdentityAdapterFactory │
│ ├─ ECC → SapEccAdapter ├─ SAP_HCM → SapHcmAdapter │
│ ├─ S4_ONPREM → SapS4OnPremAdapter ├─ SAP_S4_ONPREM → S4OnPrem… │
│ ├─ S4_CLOUD → SapS4CloudAdapter ├─ SAP_S4_CLOUD → S4Cloud… │
│ └─ MOCK → SapMockAdapter ├─ AZURE_AD → AzureAdAdapter │
│ ├─ LDAP → LdapAdapter │
│ └─ MOCK → MockAdapter │
└─────────────────────────────────────────────────────────────────────────┘
1.2 FI Posting (Masraf Muhasebeleştirme) Adapterleri
| SAP_TYPE | Adapter | Bağlantı Yöntemi | Auth | Belge Oluşturma | Not |
ECC |
SapEccAdapter |
SICF REST endpoint |
HTTP Basic (TLS) |
Z-ABAP class ZCL_EXPENSE_POSTING → BAPI_ACC_DOCUMENT_POST |
ECC 6.0+ için tek desteklenen yol; ZEXP_S_INT_* yapıları DDIC'de tanımlı olmalı. |
S4_ONPREM |
SapS4OnPremAdapter |
OData v2/v4 (Gateway) veya legacy SICF |
HTTP Basic / OAuth2 |
API_OPLACCTGDOCITEMCUBE / Z-BAPI yoluyla journal entry |
S/4 1909+; Gateway service aktif olmalı (SEGW). Müşteri Gateway kullanmıyorsa ECC adapter pattern'ı kullanılır. |
S4_CLOUD |
SapS4CloudAdapter |
REST → A_JournalEntry Cloud API |
OAuth2 (XSUAA / BTP) |
Native Cloud SDK ile; ABAP gereksinimi yok |
2402 release+; service binding üzerinden XSUAA token. F110 polling A_OperationalAcctgDoc ile. |
SAP_SF_CLOUD |
SapSuccessFactorsAdapter |
SuccessFactors OData (HR only) |
OAuth2 (SAML Assertion) |
FI yok — sadece HR / Identity sync |
1.3'te de listelenir; FI posting müşterinin başka bir SAP/ERP'sine yapılır. |
MOCK |
SapMockAdapter |
Bellek içi simülasyon |
— |
Rastgele belge no + %5 simüle hata oranı |
Dev / E2E test için. Belge no'nun son rakamı çift → polling'de PAID dönülür. |
1.3 HR / Kimlik Sync Adapterleri
| IDENTITY_PROVIDER | Adapter | Kaynak Sistem & Protokol | Auth | Sync Periyodu | Not |
SAP_HCM |
SapHcmAdapter |
SAP ECC HR — ABAP SICF endpoint /sap/bc/xpensio/user_list |
HTTP Basic / OAuth2 (ZXPENSIO_TOKEN) |
Her gece 01:00 |
PA0001 + PA0002 + HRP1000 zinciri; costCenterCode fallback chain: OPHCODE → KOSTL → COSTCENTER → RELID |
SAP_S4_ONPREM |
SapS4OnPremAdapter (Identity) |
OData API_BUSINESS_PARTNER + API_DEPARTMENT |
HTTP Basic / OAuth2 |
Her gece 01:00 |
HR-FI ayrımı olan müşteriler için; ECC HR adapter ile karıştırma. |
SAP_S4_CLOUD |
SapS4CloudAdapter (Identity) |
S/4 Cloud Identity Service (IPS / IAS) |
OAuth2 (XSUAA) |
Her gece 01:00 |
Genelde SuccessFactors ile birleşik kullanılır; standalone S/4 Cloud HR varsa devreye alınır. |
SAP_SF_CLOUD |
SapSuccessFactorsAdapter |
SuccessFactors OData v4 — EmployeeCentral |
OAuth2 (SAML Assertion) |
Her gece 01:00 |
SF master HR olan müşteriler; FI başka bir adapter ile çözülür (per-org config). |
AZURE_AD |
AzureAdAdapter |
Microsoft Graph API — /users + /groups |
OAuth2 (client_credentials, Graph scope) |
Her gece 01:00 |
Entra ID müşterileri için; grade/department extensionAttribute üzerinden veya gruplar üzerinden çözülür. |
LDAP |
LdapAdapter |
LDAP / LDAPS — RFC 4511 |
Simple Bind (DN + password) |
Her gece 01:00 |
On-prem AD, OpenLDAP. baseDN, filter, alan eşleme adminden config. |
EXTERNAL_DB |
ExternalDbAdapter |
Müşterinin doğrudan veritabanına salt-okunur view sorgusu (PostgreSQL / MSSQL / Oracle JDBC) |
DB user / password (encrypted) |
Her gece 01:00 |
Logo / Mikro / özel ERP'ler için. Müşteri tarafında v_xpensio_users view'i hazırlanır. |
MOCK |
MockAdapter |
Bellek içi seed verisi |
— |
Manuel |
Demo + E2E test için. |
NONE |
NullAdapter |
— |
— |
— |
HR sync devre dışı; kullanıcılar manuel veya Excel import ile yönetilir. |
1.4 Platform Karşılaştırma Matrisi
| Özellik | SAP ECC 6.0 | S/4 On-Prem | S/4 Cloud |
| FI Posting | BAPI_ACC_DOCUMENT_POST | BAPI compat / OData | REST Journal Entry |
| HR Sync | ABAP SICF endpoint | OData EmployeeEntity | SuccessFactors OData v4 |
| Auth | HTTP Basic | OAuth2 / Basic | OAuth2 (XSUAA) |
| ABAP Gereksinimi | Evet (7.0+) | Opsiyonel (7.50+) | Hayır |
| Kurulum Zorluğu | Orta | Orta | Düşük |
| ENV: SAP_TYPE | ECC | S4_ONPREM | S4_CLOUD |
2 Ortak Referanslar
2.1 Kullanıcı / HR Alan Eşleşmesi
| Xpensio DB | HR Sistemi Karşılığı | Açıklama |
email | E-posta | Birincil anahtar |
name | Ad + Soyad | Birleştirilmiş |
externalId | PERNR / EmployeeId | Personel No |
sapEmployeeId | PERNR | FI kalemlerinde kullanılır |
departmentCode | DEPARTMENTNO / OrgUnit | → departmentId FK |
positionCode | TITLENO / PositionId | → positionId FK |
grade | GRADE / PayGrade | 7–19 arası, onay limiti belirler |
managerEmail | MANAGEREMAIL | Yönetici → managerId FK |
isActive | '1' / 'X' = aktif | Aktiflik durumu |
2.2 Masraf → FI Mapping
| Xpensio | FI Karşılığı | Örnek |
netAmount | Net Tutar (vergi hariç) | 100.00 TRY |
taxAmount | KDV Tutarı | 20.00 TRY |
grossAmount | Brüt Tutar | 120.00 TRY |
expenseTypeCode | Masraf Türü → GL Hesap | 21 → Ulaşım GL |
taxPercentageCode | Vergi Kodu | V5 → %20 |
costCenter | Masraf Yeri (KOSTL) | 10 hane |
projectCode | WBS Elementi | Opsiyonel |
2.3 Grade → Rol Eşleştirmesi
| Grade | Unvan Tipi | Atanan Rol |
| 17–19 | VP / GM / CTO | MANAGER |
| 14–16 | Division Head | MANAGER |
| 13 | Unit Head | MANAGER |
| 7–12 | Engineer / Analyst | EMPLOYEE |
⚠️ FINANCE ve ADMIN rolleri grade ile asla değiştirilmez. Eşik: MANAGER_GRADE_THRESHOLD = 13
2.4 Çok Seviyeli Onay Zinciri
| Adım | Onaylayan | Koşul |
| 1 | MANAGER | Her zaman zorunlu |
| 2 | UPPER_MANAGER | Tutar > çalışanın grade limiti |
| 3 | CFO / ADMIN | Tutar > 50.000 TRY |
| 4 | FINANCE | Her zaman zorunlu (son adım) |
Grade Limit Örnekleri: G7–12 → 10.000 TRY | G13–15 → 25.000 TRY | G16–18 → 50.000 TRY
2.5 Vergi & Ödeme Kodları
| Vergi Kodu | Oran | Ödeme Tipi | Açıklama |
V0 | %0 | 0 | Nakit |
V1 | %1 | 1 | Kişisel Kart |
V4 | %10 | 2 | Şirket Kartı |
V5 | %20 | 3 | Kurumsal Kart |
3 SAP ECC 6.0 Entegrasyonu
IDENTITY_PROVIDER=SAP_HCM SAP_TYPE=ECC ABAP 7.0+
3.1 Kurulum Sırası
| # | Adım | SAP Tx | Açıklama |
| 1 | DDIC Nesneleri | SE11 | Tablo ve yapıları oluştur + aktive et |
| 2 | ABAP Sınıfları | SE24 | ZCL_EXPENSE_POSTING + ZCL_EXPENSE_USER_LIST |
| 3 | SICF Servisleri | SICF | Handler ata + aktive et |
| 4 | SAP Kullanıcısı | SU01 | API sistem kullanıcısı oluştur |
| 5 | Yetkilendirme | PFCG | Rol + izin nesneleri ata |
| 6 | İlk Veriler | SM30 | ZEXP_AUTH + ZEXP_CFG tabloları doldur |
| 7 | FI Uyarlama | OBA7 / FS00 / KS01 / FTXP | Belge tipi, GL, masraf yeri, vergi kodları |
3.2 DDIC Nesneleri (SE11)
ZEXP_AUTH — Kimlik Doğrulama
| Alan | Tip | Key | Açıklama |
| MANDT | CLNT 3 | ✓ | Mandant |
| TYPE | CHAR 5 | ✓ | 04=HTTP Basic, 05=Form |
| USERNAME | CHAR 100 | | API kullanıcı adı |
| PASSWORD | CHAR 100 | | API şifresi |
ZEXP_POST_LOG — FI Posting Log
| Alan | Tip | Açıklama |
| LOGID | CHAR 36 | UUID (expense ID) |
| BUKRS | BUKRS 4 | Şirket kodu |
| BELNR | BELNR 10 | SAP FI belge no |
| STATUS | CHAR 1 | S=Başarı, E=Hata |
| MESSAGE | CHAR 255 | SAP mesajı |
| RETRY_CNT | INT1 | Deneme sayısı |
ZEXP_CFG — Genel Yapılandırma
| CFGKEY | Örnek Değer | Açıklama |
| EXPENSE_GL | <GIDER_GL> | Gider GL Hesabı |
| COUNTER_GL | <KARSI_GL> | Karşı Hesap |
| KDV_GL | <KDV_GL> | İndirilecek KDV |
| DOC_TYPE | SA | Belge Tipi |
ZEXP_CFG_GL — Masraf Türü → GL Hesap Eşleşme
| Alan | Key | Açıklama |
| BUKRS | ✓ | Şirket kodu |
| SUBCOMPCODE | ✓ | Alt şirket kodu |
| EXPENSETYPECODE | ✓ | Masraf türü (21/22/23…) |
| GLACCOUNT | | GL hesap numarası |
| TAXCODE | | Vergi kodu (V0/V1/V4/V5) |
ZEXP_USERS — Kullanıcı Tablosu
| Alan | Xpensio Karşılığı | Açıklama |
| EMAIL | email (PK) | E-posta adresi |
| NAME / SURNAME | name | Ad + soyad birleştirilir |
| DEPARTMENTNO | departmentCode | Departman kodu |
| TITLENO | positionCode | Pozisyon kodu |
| GRADE | grade | Seviye (7–19), rol ataması |
| MANAGEREMAIL | managerEmail | Yönetici e-posta |
| PERSONNELCODE | externalId, sapEmployeeId | Personel numarası |
| ISACTIVE | isActive | 1=aktif, 0=pasif |
ZEXP_GRADE_POLICIES — Grade / Politika Tablosu
| Alan | Key | Açıklama |
| BUKRS | ✓ | Şirket kodu |
| GRADE | ✓ | Grade seviyesi |
| POLICYCODE | | Masraf politikası kodu |
| LIMIT_AMOUNT | | Harcama limiti (TRY) |
ZEXP_COMPANY — Şirket Yapılandırması
| Alan | Key | Açıklama |
| BUKRS | ✓ | Şirket kodu |
| COMP_NAME | | Şirket adı |
| CURRENCY | | Yerel para birimi |
| TAX_SYSTEM | | Vergi sistemi (TR/EU) |
ZEXP_S_POST_PAYLOAD — POST_EXPENSE Giriş Yapısı
COMPANYCODE (BUKRS), EMPLOYEEID (CHAR 20), EMPLOYEENAME (CHAR 100),
EXPENSEDATE (CHAR 8), POSTINGDATE (CHAR 8), DOCUMENTTYPE (BLART),
NETAMOUNT (DEC 13,2), TAXAMOUNT (DEC 13,2), GROSSAMOUNT (DEC 13,2),
TAXCODE (CHAR 2), TAXGLACCOUNT (SAKNR), CURRENCY (WAERS),
GLACCOUNT (SAKNR), COSTCENTER (KOSTL), PROJECTCODE (PS_POSID),
DESCRIPTION (CHAR 50), REFERENCE (CHAR 16), DEBUGMODE (CHAR 1)
3.3 ABAP — ZCL_EXPENSE_POSTING (FI Belge Oluşturma)
Interface: IF_HTTP_EXTENSION | SICF: /sap/bc/zexpense/post_expense
HANDLE_REQUEST — Ana Giriş Noktası
METHOD if_http_extension~handle_request.
" 1. HTTP metod kontrolü (sadece POST)
" 2. Auth doğrulama: ZEXP_AUTH → username + password
" 3. JSON body → ZEXP_S_POST_PAYLOAD'a parse
" 4. Zorunlu alan kontrolü (companycode, glaccount, netamount…)
" 5. POST_EXPENSE çağır
" 6. JSON response: { STATUS, BELNR, GJAHR, MESSAGE }
" 7. ZEXP_POST_LOG'a loglama
ENDMETHOD.
POST_EXPENSE — BAPI Çağrısı
METHOD post_expense.
" ── HEADER ──
ls_header-comp_code = is_payload-companycode.
ls_header-doc_date = is_payload-expensedate.
ls_header-pstng_date = is_payload-postingdate.
ls_header-doc_type = is_payload-documenttype.
ls_header-ref_doc_no = is_payload-reference.
ls_header-currency = is_payload-currency.
ls_header-bus_act = 'RFBU'.
" ── KALEM 1: Gider GL (Borç) ──
ls_accgl-gl_account = is_payload-glaccount.
ls_accgl-tax_code = is_payload-taxcode.
ls_accgl-costcenter = is_payload-costcenter.
ls_curr-amt_doccur = is_payload-netamount.
" ── KALEM 2: KDV GL (Borç, sadece KDV > 0) ──
IF is_payload-taxamount > 0.
ls_acctax-gl_account = is_payload-taxglaccount.
ls_curr-amt_doccur = is_payload-taxamount.
ENDIF.
" ── KALEM 3: Personel Cari (Alacak) ──
ls_accpay-vendor = is_payload-employeeid.
ls_curr-amt_doccur = - is_payload-grossamount.
" ── BAPI ÇAĞRISI ──
IF is_payload-debugmode = 'X'.
CALL FUNCTION 'BAPI_ACC_DOCUMENT_CHECK' ...
ELSE.
CALL FUNCTION 'BAPI_ACC_DOCUMENT_POST' ...
ENDIF.
" Hata kontrolü
IF RETURN tablosunda E tipi mesaj var.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ev_status = 'E'. ev_message = hata metni.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.
ev_status = 'S'. ev_belnr = belge no.
ENDIF.
ENDMETHOD.
💡 DEBUGMODE = 'X' ile BAPI_ACC_DOCUMENT_CHECK kullanılarak commit yapılmadan test edilebilir.
3.4 ABAP — ZCL_EXPENSE_USER_LIST (HR Sync)
SICF: /sap/bc/zexpense/user_list
METHOD if_http_extension~handle_request.
" ── Auth kontrolü (ZEXP_AUTH) ──
" GET / → ZEXP_USERS tablosundan JSON döndür
" GET ?action=SYNC → PA0001/PA0002'den çekip ZEXP_USERS güncelle
" - Mevcut kayıt: UPDATE
" - Yeni kayıt: INSERT
" - HR'da yok: ISACTIVE = '0'
" JSON Response: { EMPLOYEE_COUNT, SYNCED, INSERTED, DEACTIVATED }
ENDMETHOD.
⚠️ ABAP 7.0 uyumluluğu: &&, inline DATA(), string templates kullanılmaz.
3.5 SICF Servisleri
Transaction: SICF → /sap/bc/zexpense/
/post_expense → Handler: ZCL_EXPENSE_POSTING
/user_list → Handler: ZCL_EXPENSE_USER_LIST
Authentication: HTTP Basic (SAP standart)
3.6 Kullanıcı & Yetkilendirme
SU01 — Sistem Kullanıcısı
| Parametre | Değer |
| Kullanıcı Adı | ZEXP_API_USER |
| Kullanıcı Tipi | System (Dialog değil) |
| Rol | Z_EXPENSE_API_ROLE |
PFCG — Yetkilendirme Nesneleri
| Nesne | Alan | Değer |
| S_TCODE | TCD | SE16, SM30 |
| S_TABU_DIS | TABLE | ZEXP_* |
| S_ICF | ICFSERVICE | /sap/bc/zexpense/* |
| F_BKPF_BUK | BUKRS | <Şirket Kodu> |
| F_BKPF_KOA | KOART | A, D, G, K, M, S |
3.7 FI Uyarlamalar
| Tx | İşlem | Detay |
| OBA7 | Belge Tipi | SA veya özel ZK |
| FS00 | GL Hesaplar | Gider GL, Karşı Hesap, KDV GL |
| KS01 | Masraf Yeri | En az 1 aktif masraf yeri zorunlu |
| FTXP | Vergi Kodları | V0=%0, V1=%1, V4=%10, V5=%20 |
| MK01/FK01 | Vendor | Personel → Vendor eşleşmesi |
3.8 Bağlantı Yapılandırması (DB Encrypted)
💡 SAP bağlantı bilgileri .env dosyasında tutulmaz. Tüm credential'lar Xpensio Setup Wizard veya Admin Panel üzerinden girilir ve veritabanında AES-256-GCM ile şifrelenerek Organization.erpConfig alanında saklanır. Şifreler API'den okunurken otomatik maskelenir (••••••••).
Admin Panel → ERP Ayarları
| Alan | Örnek Değer | Açıklama |
erpType | ECC | SAP platform tipi |
sapBaseUrl | http://<SAP_HOST>:<PORT> | SICF base URL |
sapUsername | <API_KULLANICI> | SICF kullanıcı adı |
sapPassword | <API_SIFRESI> | 🔒 AES-256-GCM encrypted |
sapClient | <CLIENT_NO> | SAP mandant |
sapCompanyCode | <BUKRS> | Şirket kodu |
Minimal .env (Sadece sistem seviyesi)
# Sadece şifreleme anahtarı .env'de tutulur
ENCRYPTION_KEY=<64_HEX_KARAKTER> # 32-byte AES key
⚠️ ENCRYPTION_KEY production'da Docker Secret veya K8s Secret olarak yönetilmelidir. SAP kullanıcı adı/şifresi kesinlikle .env'de tutulmamalıdır.
3.9 Test Prosedürü
A) SAP Tarafı Test (SE38)
REPORT ZTEST_EXPENSE_POST.
" 1. ZEXP_S_POST_PAYLOAD yapısını doldur
" 2. DEBUGMODE = 'X' ile BAPI_ACC_DOCUMENT_CHECK çağır
" 3. RETURN tablosunu kontrol et → hata yoksa DEBUGMODE = '' ile tekrarla
" 4. BELNR alındı → FB03 ile belgeyi doğrula
B) REST Client Testi
curl -X POST http://<SAP_HOST>:<PORT>/sap/bc/zexpense/post_expense \
-H "Content-Type: application/json" \
-u "<USER>:<PASS>" \
-d '{
"COMPANYCODE":"<BUKRS>","EMPLOYEEID":"<VENDOR_NO>",
"EXPENSEDATE":"20260324","POSTINGDATE":"20260324",
"DOCUMENTTYPE":"SA","NETAMOUNT":100,"TAXAMOUNT":0,
"GROSSAMOUNT":100,"TAXCODE":"V0","CURRENCY":"TRY",
"GLACCOUNT":"<GL>","COSTCENTER":"<KY>",
"DESCRIPTION":"Test","REFERENCE":"TEST-001","DEBUGMODE":"X"
}'
C) Xpensio Uçtan Uca Test
POST /api/v1/identity/sync → Kullanıcılar SAP'den çekildi
- Dashboard → Yeni masraf oluştur → Onayla
- Muhasebe → SAP'ye Gönder → Durum:
POSTED_TO_SAP
- SAP FB03 ile belge numarasını doğrula
3.10 Kurulum Kontrol Listesi
SAP Tarafı
- DDIC nesneleri oluşturuldu ve aktive edildi (SE11)
- ZCL_EXPENSE_POSTING sınıfı oluşturuldu (SE24)
- ZCL_EXPENSE_USER_LIST sınıfı oluşturuldu (SE24)
- SICF servis node'ları aktive edildi
- ZEXP_API_USER sistem kullanıcısı oluşturuldu (SU01)
- Z_EXPENSE_API_ROLE rol atandı (PFCG)
- ZEXP_AUTH tablosu dolduruldu (SM30)
- ZEXP_CFG + ZEXP_CFG_GL tabloları dolduruldu (SM30)
- GL hesaplar, masraf yerleri, vergi kodları tanımlandı
- Personel → Vendor FI eşleşmesi yapıldı
- DEBUGMODE=X ile test postu başarılı
- Gerçek posting ile BELNR alındı ve FB03'te doğrulandı
Xpensio Tarafı
- Admin Panel → ERP Ayarları üzerinden SAP bağlantı bilgileri girildi
- Identity sync başarılı (
POST /api/v1/identity/sync)
- Grade dağılımı ve manager zinciri doğrulandı
- Test masrafı → Onayla → SAP POST →
POSTED_TO_SAP
4 S/4HANA On-Premise
IDENTITY_PROVIDER=SAP_S4_ONPREM SAP_TYPE=S4_ONPREM ABAP 7.50+
4.1 ECC ile Temel Farklar
| Özellik | ECC 6.0 | S/4HANA On-Prem |
| Muhasebe | Klasik FI (BKPF/BSEG) | Universal Journal (ACDOCA) |
| ABAP | 7.0+ (eski syntax) | 7.50+ (inline DATA, string templates) |
| FI Posting | BAPI_ACC_DOCUMENT_POST | BAPI compat veya OData v4 |
| HR Sync | Custom ABAP | OData EmployeeEntity veya HCM compat |
| Silinen Tablolar | BSEG, BSIS, BSAS… | Compatibility view olarak mevcut |
💡 S/4HANA Universal Journal (ACDOCA), tüm FI/CO/ML/AA girişlerini tek tabloda birleştirir. Xpensio BAPI'si bu katmanın üzerinde çalışır.
4.2 FI Posting Yaklaşımları
Yaklaşım A — BAPI Compat (Önerilen, En Hızlı Kurulum)
S/4HANA BAPI_ACC_DOCUMENT_POST'u desteklemeye devam eder. Bölüm 3.2–3.7'deki ECC ABAP kodu ve DDIC nesneleri birebir çalışır. Tek değişiklik:
SAP_TYPE=S4_ONPREM # (ECC yerine)
Yaklaşım B — OData v4 Journal Entry API
ABAP geliştirme yapmadan doğrudan S/4HANA standart OData servisi kullanılır:
POST /sap/opu/odata/sap/API_JOURNALENTRYITEMBASIC_SRV/JournalEntryItem
Authorization: Basic <base64>
Content-Type: application/json
{
"CompanyCode": "<BUKRS>",
"PostingDate": "2026-03-24",
"JournalEntryType": "SA",
"to_JournalEntryItem": {
"results": [
{ "GLAccount": "<GIDER_GL>", "DebitCreditCode": "S",
"AmountInTransactionCurrency": "100.00", "CostCenter": "<KY>" },
{ "GLAccount": "<KARSI_GL>", "DebitCreditCode": "H",
"AmountInTransactionCurrency": "120.00" }
]
}
}
⚠️ OData yaklaşımı için /IWFND/MAINT_SERVICE'de servis aktive edilmeli + x-csrf-token yönetimi gerekli.
4.3 HR / Kimlik Sync
Seçenek A — HCM Compat: HCM modülü mevcutsa → Bölüm 3.4'teki ABAP user_list aynen uygulanır.
Seçenek B — OData EmployeeEntity:
GET /sap/opu/odata/sap/HCMFAB_EMPLOYEE_SRV/EmployeeCollection
?$select=EmployeeId,FirstName,LastName,EmailAddress,
OrganizationalUnit,Position,Grade
&$filter=IsActive eq true
Bu yaklaşımda ABAP geliştirme gerekmez; IDENTITY_PROVIDER=SAP_S4_ONPREM ile otomatik seçilir.
4.4 Bağlantı Yapılandırması (DB Encrypted)
Bölüm 3.8'deki yapı aynen geçerlidir. Admin Panel → ERP Ayarları:
| Alan | Örnek Değer | Açıklama |
erpType | S4_ONPREM | Platform tipi |
sapBaseUrl | https://<S4_HOST>:<PORT> | S/4 base URL |
sapUsername | <API_KULLANICI> | SICF veya OData kullanıcısı |
sapPassword | <API_SIFRESI> | 🔒 AES-256-GCM encrypted |
sapClient | <CLIENT_NO> | SAP mandant |
sapCompanyCode | <BUKRS> | Şirket kodu |
odataServicePath | /sap/opu/odata/sap/API_JOURNAL… | OData yaklaşımında ek path |
4.5 Kontrol Listesi
- BAPI compat: ECC Bölüm 3.10 kontrol listesinin tamamı uygulandı
- OData:
/IWFND/MAINT_SERVICE servisleri aktive edildi
- HTTPS sertifikası SAP ICM'e yüklendi (STRUST)
- Universal Journal (ACDOCA) konfigürasyonu doğrulandı
- ENV
SAP_TYPE=S4_ONPREM olarak ayarlandı
- HR sync (HCM veya OData) testi başarılı
- FI Posting testi başarılı, BELNR alındı
5 S/4HANA Cloud + SuccessFactors
IDENTITY_PROVIDER=SAP_S4_CLOUD SAP_TYPE=S4_CLOUD ABAP Gerekmez
5.1 OAuth 2.0 Kurulumu (XSUAA / BTP)
- BTP Cockpit → Subaccount → Service Marketplace → S/4HANA Cloud aboneliği
- Service Instance oluştur →
clientid ve clientsecret al
- Scope'lara Journal Entry API erişimi ekle
Token Endpoint
POST https://<XSUAA>.authentication.<REGION>.hana.ondemand.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=<CLIENT_ID>
&client_secret=<CLIENT_SECRET>
💡 Token süresi genellikle 1800sn (30dk). Xpensio expire öncesi otomatik yeniler.
5.2 FI Posting — Journal Entry API
Adım 1: CSRF Token Al
GET /sap/opu/odata/sap/API_JOURNALENTRYITEMBASIC_SRV/$metadata
Authorization: Bearer <TOKEN>
x-csrf-token: Fetch
→ Response Header: x-csrf-token: <CSRF_VALUE>
Adım 2: Journal Entry Oluştur
POST /sap/opu/odata/sap/API_JOURNALENTRYITEMBASIC_SRV/JournalEntryItem
Authorization: Bearer <TOKEN>
x-csrf-token: <CSRF_VALUE>
Content-Type: application/json
{
"CompanyCode": "<BUKRS>",
"AccountingDocumentType": "SA",
"DocumentReferenceID": "<EXPENSE_ID>",
"PostingDate": "2026-03-24",
"to_JournalEntryItem": {
"results": [
{ "GLAccount": "<GIDER_GL>", "DebitCreditCode": "S",
"AmountInTransactionCurrency": "100.00",
"CostCenter": "<KY>", "TaxCode": "V5" },
{ "GLAccount": "<KARSI_GL>", "DebitCreditCode": "H",
"AmountInTransactionCurrency": "120.00",
"Vendor": "<TEDARIKCI_NO>" }
]
}
}
5.3 HR Sync — SuccessFactors Employee Central API
SuccessFactors OAuth 2.0
POST https://<SF_HOST>/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=<SF_CLIENT_ID>
&client_secret=<SF_CLIENT_SECRET>
&company_id=<SF_COMPANY_ID>
Çalışan Listesi
GET https://<SF_HOST>/odata/v4/sfsf/User
?$select=userId,firstName,lastName,email,department,
jobTitle,managerId,payGrade
&$filter=status eq 'active'
&$top=1000
Authorization: Bearer <SF_TOKEN>
Departman Listesi
GET https://<SF_HOST>/odata/v4/sfsf/FODepartment
?$select=departmentId,name,headOfUnit,parentUnit
&$filter=effectiveStatus eq 'A'
Pozisyon Listesi
GET https://<SF_HOST>/odata/v4/sfsf/Position
?$select=positionCode,externalName,payGrade
&$filter=effectiveStatus eq 'A'
5.4 SuccessFactors → Xpensio Alan Eşleşmesi
| SF OData Alanı | Xpensio DB | Not |
userId | externalId | SF kullanıcı ID |
email | email | PK — eşleşme anahtarı |
firstName + lastName | name | Birleştirilir |
department | departmentCode | → departmentId FK |
jobTitle / position | jobTitle | Unvan |
managerId → email resolve | managerEmail | 2. sorgu ile resolve |
payGrade | grade | Sayısal (7–19) |
status='active' | isActive=true | |
5.5 Bağlantı Yapılandırması (DB Encrypted)
Bölüm 3.8'deki yapı aynen geçerlidir. Admin Panel → ERP Ayarları:
| Alan | Örnek Değer | Açıklama |
erpType | S4_CLOUD | Platform tipi |
s4CloudBaseUrl | https://<S4CLOUD_HOST> | S/4 Cloud API base |
s4CloudTokenUrl | https://<XSUAA>.authentication… | XSUAA token endpoint |
s4CloudClientId | <CLIENT_ID> | OAuth2 client |
s4CloudClientSecret | <CLIENT_SECRET> | 🔒 AES-256-GCM encrypted |
sapCompanyCode | <BUKRS> | Şirket kodu |
sfBaseUrl | https://<SF_HOST>/odata/v4/sfsf | SuccessFactors OData |
sfTokenUrl | https://<SF_HOST>/oauth/token | SF OAuth2 token |
sfClientId | <SF_CLIENT_ID> | SF OAuth2 client |
sfClientSecret | <SF_CLIENT_SECRET> | 🔒 AES-256-GCM encrypted |
sfCompanyId | <SF_COMPANY_ID> | SF şirket ID |
5.6 Kontrol Listesi
SAP BTP / S/4HANA Cloud
- BTP Subaccount oluşturuldu
- OAuth2 client oluşturuldu, clientid/secret alındı
- Journal Entry API yetkisi service binding'e eklendi
- Token alınıyor + OData $metadata çekilebiliyor
- Test journal entry başarılı
SuccessFactors
- EC Admin: API User / OAuth2 Client oluşturuldu
- Employee, FODepartment, Position OData erişimi verildi
- API test: User koleksiyonundan aktif çalışanlar listeleniyor
- managerId → email resolve çalışıyor
Xpensio
- Admin Panel → ERP Ayarları üzerinden bağlantı bilgileri girildi (DB encrypted)
- S/4 Cloud token yenileme çalışıyor (expire öncesi otomatik)
- SF token yenileme çalışıyor
- Identity sync başarılı, kullanıcılar + departmanlar + pozisyonlar oluştu
- FI Posting testi → POSTED_TO_SAP durumu OK
5b Kurumsal Kart Mutabakatı & UMSKZ Akışı
Xpensio, kurumsal kredi kartı ekstresini içeri alarak satırları masraf kayıtlarıyla otomatik eşler ve eşleşmiş satırları mevcut SAP FI Push akışına teslim eder. Banka tarafına ek bir RFC veya web servisi gerekmez — eşleşmiş kayıtlar BAPI_ACC_DOCUMENT_POST üzerinden standart yolla post edilir.
5b.1 Muhasebe Yansıması (UMSKZ Eşlemesi)
| Kart Tipi | Ödeme Yöntemi | UMSKZ | SAP Hesap | Açıklama |
| CORPORATE (Şirket KK) | 3 — Kurumsal Kart | O | 309 — Şirket KK | Borç: Gider GL · Alacak: 309 (Banka tarafından kesilen kurumsal kart) |
| PERSONAL (Şahsi Kart) | 1 — Şahsi Kart | I | 195 — İş Avansı | Borç: Gider GL · Alacak: 195 (Personel iadesi sonrası kapanır) |
| NAKİT | 0 — Nakit | N | — | Borç: Gider GL · Alacak: 100 Kasa |
📌 ZEXP_CFG_02 tablosundaki UMSKZ kodları ile birebir uyumludur. 0=N · 1=O · 2=I · 3=N
5b.2 İş Akışı
- Ekstre import: Banka CSV/PDF/Excel dosyası Finance tarafından yüklenir. Parser tarih/tutar/merchant/currency çıkarır, satırlar UNMATCHED olarak kayıt edilir.
- Auto-match: Skor algoritması (tarih ±2 gün, tutar ±%0.5–2 FX, merchant fuzzy, fatura/VKN bonus) ≥ 80 olan satırları masrafa bağlar.
- Manuel + bölme: Kalan satırlar Finance tarafından elle bağlanır veya N parçaya bölünür.
- SAP Push: Bağlanmış masraf zaten standart onay zincirini geçmişse mevcut SAP FI Push pipeline'ı tetiklenir; UMSKZ kart tipinden türetilir.
5b.3 Tenant Başına Banka Şablonu
Müşterinin kullandığı banka standart Garanti/İş/Akbank parserlarımızdan farklıysa, admin "CSV Şablonları" sekmesinden kolon eşleştirmesi tanımlar:
dateCol — header satırındaki tarih kolonunun adı
amountCol — tutar kolonu adı
descriptionCol — açıklama kolonu (opsiyonel)
skipRows — header öncesi atlanacak satır sayısı (banka logo/başlık satırları için)
Yükleme dropdown'unda "Özel: {şablon adı}" olarak görünür ve seçilince bankFormat=custom:NAME olarak iletilir.
5b.4 Çok Döviz
USD/EUR/GBP harcamalar canlı kurla TRY karşılığına çevrilerek karşılaştırılır. Cross-currency tolerans %2 (TRY/TRY için %0.5). Kur kaynağı: FxRateService — open.er-api.com (1 saatlik cache + admin manuel override).
6 Güvenlik & Ağ Gereksinimleri
6.1 Ağ & Firewall
| Kaynak | Hedef | Port | Protokol |
| Xpensio Backend | SAP ECC/S4 SICF | 8000/44300 | HTTPS |
| Xpensio Backend | S/4 Cloud API | 443 | HTTPS (OAuth2) |
| Xpensio Backend | SuccessFactors API | 443 | HTTPS (OAuth2) |
| Xpensio Backend | BTP XSUAA Token | 443 | HTTPS |
✅ SAP/ERP sunucusu ile Xpensio backend arasında VPN veya özel ağ (private link) bağlantısı önerilir.
6.2 Kimlik Bilgileri Yönetimi — erpConfig AES-256-GCM
- SAP kullanıcı adı, şifre, client secret gibi hassas bilgiler
.env dosyasında tutulmaz
- Tüm SAP bağlantı bilgileri veritabanında
Organization.erpConfig alanında AES-256-GCM ile şifrelenerek saklanır
- Şifreleme anahtarı (
ENCRYPTION_KEY) tek .env parametresidir — production'da Docker Secret veya K8s Secret olarak yönetilir
- Setup Wizard veya Admin Panel → ERP Ayarları üzerinden girilen bilgiler otomatik şifrelenir
- API'den config okunurken password/secret alanları otomatik maskelenir (
••••••••)
- Config güncelleme sırasında maskeli alanlar korunur (mevcut değer override edilmez)
- Kaynak koda credential bilgisi asla gömülmez
Şifreleme Akışı
| Adım | Detay |
| Algoritma | aes-256-gcm (Node.js crypto modülü — authenticated encryption) |
| Anahtar | ENCRYPTION_KEY env var — 32 byte (64 hex karakter). openssl rand -hex 32 ile üretilir. |
| IV | Her şifrelemede yeniden üretilen 12 byte random IV (NIST SP 800-38D önerisi) |
| Auth Tag | 16 byte — şifrelemenin bütünlüğünü doğrular (tampering korunması) |
| Saklama Formatı | v1:<iv-hex>:<authtag-hex>:<ciphertext-hex> — versiyon prefix'i ileride rotasyon için |
| Encode | JSON.stringify(config) → utf-8 → AES-GCM → hex; ters yönde JSON.parse |
| Scope | Sadece Organization.erpConfig kolonunda. Diğer DB kolonları (email, password hash vb.) ayrı mekanizmalarla korunur. |
⚠️ Anahtar Kaybı Felaketi: ENCRYPTION_KEY kaybedilirse hiçbir tenant'ın SAP yapılandırması okunamaz. Backup & restore akışlarında bu değer DB dump ile birlikte güvenli kasada (vault) tutulmalı. Anahtar rotasyonu manuel iştir: eski anahtar ile decrypt → yeni anahtar ile re-encrypt → versiyon prefix güncellenir.
Şifrelenen Alanlar (örnek erpConfig payload)
{
"sapType": "S4_ONPREM",
"baseUrl": "https://sap.musteri.com:44300",
"username": "XPENSIO_API",
"password": "•••••••• (encrypted at rest)",
"clientSecret": "•••••••• (encrypted at rest)",
"client": "100",
"language": "TR",
"ca": "-----BEGIN CERTIFICATE----- ... (encrypted at rest)",
"glConfig": {
"byCompany": {
"1000": {
"expenseGl": "770000",
"taxGl": "190000",
"expenseCostCenter": "10001",
"paymentConfig": { "umskz": "0", "payableGl": "335000" }
}
}
}
}
Güvenlik Kontrolleri
- API yanıtı:
GET /admin/organization → password/secret alanları otomatik maskelenir; clear-text hiçbir endpoint'ten dönmez
- Audit log: Her
erpConfig değişikliği AuditLog'a (user + timestamp + targetField) yazılır
- Test ortamı: Dev'de
ENCRYPTION_KEY ayrı (basit / sabit), production key dev/staging'e asla kopyalanmaz
- Anahtar rotasyonu prosedürü: (1) Tüm org'lar için eski anahtarla
erpConfig decrypt → JSON; (2) yeni anahtarla encrypt → DB güncelle; (3) ENCRYPTION_KEY env güncellenip restart
6.3 SAP Tarafı Güvenlik
- TLS: SICF dahil tüm HTTP çağrıları HTTPS olmalı (SAP ICM SSL sertifikası — STRUST)
- IP Kısıtlaması: SICF servis erişimini sadece Xpensio backend IP'sine kısıtlayın
- Least Privilege: API kullanıcısına yalnızca gerekli yetkilendirme nesneleri verilmeli
- Parola Politikası: API kullanıcısı parolası 90 günde bir rotasyona tabi tutulmalı
- Denetim: SAP SM21 (system log) / ST22 (dump analizi) loglarını periyodik kontrol edin
- API Kullanıcısı: System tipinde oluşturun (Dialog değil), interaktif oturum açmasın
§7. 2026 SAP Yenilikleri (Mayıs Sürümü)
Bu bölüm canlı kodda son sprint'te (Mayıs 2026) eklenen SAP entegrasyonuyla ilgili yenilikleri özetler.
7.1 Per-Org SAP Adapter
Her organizasyon kendi Organization.erpConfig + adapter instance'ı ile çalışır. Multi-tenant izolasyonu tam — bir müşterinin SAP credential'ları başka bir müşterinin sorgularında kullanılamaz. SapAdapterFactory her request'te orgId üzerinden adapter çözümler.
7.2 KKEG Otomatik Split (7194)
Personel araç giderleri ve diğer kanunen kabul edilmeyen giderler hem PUSH hem PULL akışında otomatik ayrıştırılır. gl_kkeg_mappings tablosu (/admin/gl-kkeg-mappings) ile yönetilir. SAP FI'ya KKEGGLACCOUNT ve KKEGTAXGLACCOUNT alanları doğru hesaplara düşer.
7.3 F110 Ödeme Polling
Günlük 09:00 cron payment-polling.service.ts üzerinden F110 raporu çekilir, POSTED_TO_SAP statüsündeki masraflar eşleştirilir, ödenenler PAID statüsüne geçer. Çalışan mobil/web'de canlı görür.
7.4 Per-User Cost Center Whitelist
Yeni UserCostCenterAccess M2M tablosu. resolveAllowedCostCenters async resolver: EMPLOYEE/MANAGER kendi RELID + whitelist; FINANCE/ADMIN whitelist boşsa serbest, doluysa kısıtlı. Yetkisiz CC seçimi 403 döner. Admin panel: /admin/users modal → "Yetkili Masraf Yerleri" çoklu seçim.
7.5 Mükerrer Fiş VKN Kontrolü
expenses.service.ts create akışında receiptNumber + merchantTaxId çifti unique check'i. Aynı fiş + aynı satıcı VKN ile ikinci masraf 400 BadRequest döner.
7.6 GL Bakım Modülleri
İki ayrı admin ekranı: /admin/gl-mappings (standart GL eşleştirmeleri) ve /admin/gl-kkeg-mappings (KKEG split kuralları). Her ikisi de Excel ile toplu içe aktarma destekler. computeKkegSplit servis fonksiyonu personel araç giderini Personel + KKEG hesabı olarak ikiye böler.
Xpensio SAP Entegrasyon Teknik Kılavuzu v2.1 — Mayıs 2026