Skip to content

Payment In Complete Walkthrough — Example-Based Documentation

Overview

This document demonstrates the complete lifecycle of a Payment In transaction using real payload examples, showing exactly which tables and columns are affected during Add (Draft), Post, and Unpost phases.

A Payment In records money received from a customer (or other payer) into a bank account or treasury. It can optionally:

  • Reconcile against one or more outstanding Sales Invoices
  • Apply as a Customer Advanced Payment (received before any invoice exists)
  • Include a payment method commission (e.g. bank transfer fee, cheque commission) with optional VAT

Example Payload — Customer Invoice Payment (Bank Transfer)

json
{
  "paymentInDate": "2026-01-28T16:30:00",
  "description": "Payment for SI-2026-0001",
  "currencyId": 4,
  "rate": 1.0,
  "paymentHub": "Bank",
  "paymentHubDetailId": 12,
  "isCustomerAdvancedPayment": false,
  "isAmountIncludesVat": false,
  "financialYearPeriodId": "FY-2026-Jan",
  "paymentInDetails": [
    {
      "paidBy": "Customer",
      "paidByDetailsId": 433,
      "paymentMethodId": 5,
      "amount": 1150.00,
      "currencyId": 4,
      "rate": 1.0,
      "costCenters": [],
      "paymentMethodDetail": {
        "chequeNumber": null,
        "chequeDueDate": null,
        "bankReference": "TRF-20260128-001",
        "commissionType": null,
        "commissionValue": 0,
        "allowVat": false,
        "vatRatio": 0
      }
    }
  ]
}

Pre-Save Calculations

Detail-Level:
  LocalAmount     = Amount × Rate       = 1150 × 1.0 = 1150
  CommissionAmount = 0  (no commission)
  VatAmount        = 0  (no VAT)
  NetAmount       = Amount - CommissionAmount - VatAmount = 1150 - 0 - 0 = 1150
  NetLocalAmount  = NetAmount × Rate    = 1150 × 1.0 = 1150

Header Totals:
  Amount          = Sum of detail amounts          = 1150
  LocalAmount     = Sum of detail local amounts    = 1150
  NetAmount       = Sum of detail net amounts      = 1150
  NetLocalAmount  = Sum of detail net local amounts = 1150

Phase 1: Add Payment In (Draft)

Handler: AddPaymentInCommandHandler

Action: Creates a draft payment-in record with no GL or bank impact.

Validations Performed

CheckRuleResult
Payment date in open periodResolved via GetCurrentPeriodQuery(PaymentInDate)✅ Jan 2026 open
Currency requiredCurrencyId must be provided✅ SAR (4) provided
Payment hubMust be Bank or Treasury✅ Bank
PaymentHubDetailId requiredMust be provided — resolves to BankAccountId (hub=Bank) or TreasuryId (hub=Treasury)✅ 12 provided
Detail paid-byPaidBy must be Customer, Vendor, or Other✅ Customer
Paid-by entityPaidByDetailsId must reference valid customer✅ Customer 433
Payment methodMust reference valid PaymentMethod✅ Method 5 (Transfer)
Amount > 0Each detail amount must be positive✅ 1150 > 0
Advanced payment rulesIf IsCustomerAdvancedPayment = true, only one detail allowed✅ Not advanced
Cheque fieldsIf PaymentMethodType = Check, ChequeNumber + ChequeDueDate required✅ Not cheque
Cost center sumIf account requires cost centers, percentages must sum to 100%✅ No cost centers required

Table 1: PaymentInHeader (INSERT)

Operation: INSERT new record

Column NameValueSourceNotes
Id[Auto-Generated GUID]Systeme.g., a1b2c3d4-1234-5678-abcd-ef0123456789
Code"PI-2026-0001"Sequence ServiceGenerated by UpdateLastSequenceCommand
PaymentInDate2026-01-28 16:30:00PayloadTransaction date
Description"Payment for SI-2026-0001"PayloadOptional notes
Status"Draft"SetAsDraft()TransactionStatus enum
PaymentHub"Bank"PayloadPaymentPlace enum: Bank or Treasury
PaymentHubDetailId12PayloadHolds BankAccountId when PaymentHub = Bank; holds TreasuryId when PaymentHub = Treasury
CurrencyId4PayloadSaudi Riyal
Rate1.0PayloadExchange rate to base currency
Amount1150.00CalculatedSum of detail amounts
LocalAmount1150.00Amount × RateBase currency amount
NetAmount1150.00Amount - Commission - VATNet after deductions
NetLocalAmount1150.00NetAmount × RateBase currency net
IsCustomerAdvancedPaymentfalsePayloadNot an advance payment
IsAmountIncludesVatfalsePayloadVAT not included in amount
TaxIdNULLPayloadTax definition (used for advanced payments)
AccountIdNULLPayloadOverride GL account (optional)
FinancialYearPeriodId[Integer DB ID]GetCurrentPeriodQuery(PaymentInDate)Resolved from date — payload financialYearPeriodId string is for display only
JournalIdNULLDraft stateSet on post
JournalCodeNULLDraft stateSet on post
SourceDocumentTypeNULLNot from SOSet for system-generated payments
SourceDocumentIdNULLNot from SOReference to source transaction
SourceDocumentCodeNULLNot from SOSource transaction code
WorkflowStatusNULLNo workflow triggered yetRequestStatus enum
ExternalIdentifierNULLNot externalExternal system reference
ExternalCodeNULLNot externalExternal payment code
POSSessionIdNULLNot POSPOS session reference
BranchId[Current Branch]ISecurityServiceBranch context
CompanyId[Current Company]ISecurityServiceCompany context
CreatedDate[Current Timestamp]AuditAuto-set
CreatedBy[Current User ID]ISecurityServiceAuthenticated user
TenantId[Tenant GUID]ISecurityServiceMulti-tenancy isolation
IsDeletedfalseDefaultSoft delete flag

Table 2: PaymentInDetail (INSERT)

Operation: INSERT one record per detail line

Column NameValueSourceNotes
Id[Auto-Generated GUID]SystemDetail line ID
PaymentInHeaderId[Header GUID]FKParent payment-in
PaidBy"Customer"PayloadPaidBy enum: Customer / Vendor / Other
PaidByDetailsId433PayloadCustomer ID (FK to Customer table)
CustomerName"dubai"ResolvedCustomer display name
CustomerNameAr"دبي"ResolvedArabic customer name
VendorIdNULLNot vendorSet when PaidBy = Vendor
SalesManIdNULLPayloadOptional salesman reference
PaymentMethodId5PayloadReferences PaymentMethod table
Amount1150.00PayloadIn foreign currency
LocalAmount1150.00Amount × RateBase currency
NetAmount1150.00Amount - Commission - VATAfter deductions
NetLocalAmount1150.00NetAmount × RateBase currency net
Rate1.0PayloadExchange rate
CurrencyId4PayloadSaudi Riyal
ReconciledAmount0DefaultNo reconciliation yet
AmountToReconcile1150.00= NetLocalAmountFull amount available to reconcile
AccountIdNULLOptionalOverride GL account for this line
CreatedDate[Current Timestamp]AuditAuto-set
CreatedBy[Current User ID]ISecurityServiceAuthenticated user
TenantId[Tenant GUID]ISecurityServiceMulti-tenancy

Table 3: PaymentInMethodDetail (INSERT)

Operation: INSERT one record per detail (stores payment method specifics)

Column NameValueSourceNotes
Id[Auto-Generated GUID]SystemMethod detail ID
PaymentInDetailId[Detail GUID]FKParent detail line
PaymentMethodId5PayloadPaymentMethod reference
ChequeNumberNULLNot chequePopulated for Check type
ChequeDueDateNULLNot chequePopulated for Check type
BankReference"TRF-20260128-001"PayloadBank transfer reference
CommissionAmount0Calculated0 — no commission configured
VatAmount0Calculated0 — AllowVat = false
CommissionTypeNULLNo commissionAmount or Percent
CommissionValue0PayloadCommission percentage or amount
CommissionAccountIdNULLNo commissionGL account for commission expense
AllowVatfalsePayloadVAT on commission disabled
VatRatio0Payload0% VAT on commission
VatAccountIdNULLNo VATGL account for commission VAT
CreatedDate[Current Timestamp]AuditAuto-set

Table 4: PaymentInDetailCostCenter (INSERT)

Operation: NONE — no cost centers provided for this payment

When cost centers are required (account's CostCenterConfig = Mandatory):

Column NameValueSourceNotes
Id[Auto-Generated GUID]SystemAllocation ID
PaymentInDetailId[Detail GUID]FKParent detail
CostCenterId[e.g. 87]PayloadCost center reference
Percentage100.0PayloadAllocation percentage
Amount1150.00Detail.NetLocalAmount × Percentage/100Allocated amount

Summary of Add Phase (Draft)

Tables Affected:

  • ✅ PaymentInHeader — 1 INSERT
  • ✅ PaymentInDetail — 1 INSERT
  • ✅ PaymentInMethodDetail — 1 INSERT
  • ❌ PaymentInDetailCostCenter — 0 (no cost centers in this example)
  • ❌ GL / Bank / Treasury — NO impact (draft only)

Phase 2: Post Payment In

Handler: PostPaymentInCommandHandler

Action: Finalizes the payment, creates a Journal Entry, records a Bank Transaction, and optionally reconciles Sales Invoices.

Prerequisites Check

CheckRule
Status = DraftCannot post already-posted payment
GL account for customerCustomer must have Receivable Account configured
GL account for payment methodPaymentMethod must have a GL account (e.g. bank clearing account)
GL account for commission (if any)CommissionAccountId must be set
GL account for commission VAT (if any)VatAccountId must be set when AllowVat = true
Open financial periodPaymentInDate period must be open

Table 1: PaymentInHeader (UPDATE)

Operation: UPDATE existing record

Column NameBefore (Draft)After (Posted)Notes
Status"Draft""Posted"TransactionStatus enum
JournalIdNULL[Journal GUID]Sales journal entry ID
JournalCodeNULL"JE-2026-0125"Journal entry code
UpdatedDateNULL[Current Timestamp]Last update timestamp
UpdatedByNULL[Current User ID]User who posted

Table 2: JournalEntry (INSERT — PaymentIn Journal)

Operation: INSERT via IAccountingPublicApi.AddJournal()

Type: PaymentIn

Column NameValueNotes
Id[Auto-Generated GUID]Journal ID
Code"JE-2026-0125"Sequence code
JournalDate2026-01-28 16:30:00From PaymentInDate
Type"PaymentIn"JournalEntryType enum
SourceDocument"PaymentIn"SourceDocument enum
SourceDocumentId[PaymentInHeader GUID]Link to payment
SourceDocumentCode"PI-2026-0001"Payment code
Status"Posted"Immediately posted
TotalDebit1150.00Sum of debit lines
TotalCredit1150.00Sum of credit lines (balanced)
FinancialYearPeriodId[Period ID]From payment period
Description"Payment for SI-2026-0001"From payment description

Table 3: JournalEntryLine (INSERT × 2 — PaymentIn Journal)

Line 1: Bank Account (Debit)

Money received goes into the bank:

ColumnValueNotes
AccountId[BankAccount.GLAccountId]GL account of bank account 12
AccountCode"1020"e.g. Current Bank Account
DebitAmount1150.00Full received amount
CreditAmount0No credit
DebitAmountLocal1150.00× Rate (1.0)
CurrencyId4SAR
CurrencyRate1.0Base currency
CostCenterIdNULLNo cost center for bank

Line 2: Accounts Receivable (Credit)

Customer's outstanding balance reduced:

ColumnValueNotes
AccountId[Customer.ReceivableAccountId]AR account for customer 433
AccountCode"1010"Accounts Receivable
DebitAmount0No debit
CreditAmount1150.00Clears customer balance
CreditAmountLocal1150.00× Rate (1.0)
CurrencyId4SAR
CurrencyRate1.0Base currency
CostCenterIdNULLNo cost center for AR
Journal JE-2026-0125 — Payment In

  DR  1020  Bank Account (Current)    1,150.00
      CR  1010  Accounts Receivable            1,150.00
                                     ---------  ---------
      Total                          1,150.00   1,150.00

Table 4: BankTransactionHeader (INSERT)

Operation: INSERT — records this payment in the bank's transaction ledger

Column NameValueNotes
Id[Auto-Generated GUID]Transaction ID
BankAccountId12Receiving bank account
TransactionDate2026-01-28From PaymentInDate
TransactionType"In"Money coming in
Amount1150.00Payment amount
LocalAmount1150.00Base currency
SourceDocumentType"PaymentIn"Reference type
SourceDocumentId[PaymentInHeader GUID]Link to payment
SourceDocumentCode"PI-2026-0001"Payment code
JournalId[Journal GUID]Link to journal
Status"Posted"Always posted
CreatedDate[Current Timestamp]Audit

Table 5: BankTransactionDetail (INSERT)

Operation: INSERT — one per payment detail line

Column NameValueNotes
BankTransactionHeaderId[Header GUID]Parent transaction
PaymentInDetailId[Detail GUID]Link to payment detail
Amount1150.00Detail amount
LocalAmount1150.00Base currency
PaidBy"Customer"Payer type
PaidByDetailsId433Customer ID

Table 6: CustomerFinancial (UPDATE)

Operation: UPDATE — customer's financial summary

ColumnBeforeAfterNotes
TotalPayments01150.00+= NetLocalAmount
OutstandingBalance1150.000.00-= NetLocalAmount
AvailableCredit-1150.000.00CreditLimit - OutstandingBalance

Summary of Post Phase

Tables Affected:

  • ✅ PaymentInHeader — 1 UPDATE (status, journal IDs)
  • ✅ JournalEntry — 1 INSERT (PaymentIn journal, immediately Posted)
  • ✅ JournalEntryLine — 2 INSERTs (Bank DR + AR CR)
  • ✅ BankTransactionHeader — 1 INSERT
  • ✅ BankTransactionDetail — 1 INSERT
  • ✅ CustomerFinancial — 1 UPDATE

GL Impact:

Account 1020 (Bank Account)         DR  1,150.00
Account 1010 (Accounts Receivable)      CR  1,150.00

Phase 3: Auto-Reconcile Sales Invoice on Post

When a payment is posted and reconciliation is enabled, the system links the payment to the outstanding invoice balance.

Table: SalesInvoiceReconciliation (INSERT)

Column NameValueNotes
Id[Auto-Generated GUID]Reconciliation record
PaymentInDetailId[Detail GUID]Payment line
SalesInvoiceHeaderId[Invoice GUID]Reconciled invoice
SalesInvoiceBalanceId[Balance GUID]Installment reconciled
Amount1150.00Reconciled amount
LocalAmount1150.00Base currency
ReconciliationDate2026-01-28Date of reconciliation

SalesInvoiceBalance (UPDATE)

ColumnBeforeAfter
DueBalance1150.000.00
LocalDueBalance1150.000.00

SalesInvoiceHeader (UPDATE)

ColumnBeforeAfter
ReconciledAmount0.001150.00
AmountToReconcile1150.000.00
IsFullyReconciledfalsetrue

PaymentInDetail (UPDATE)

ColumnBeforeAfter
ReconciledAmount0.001150.00
AmountToReconcile1150.000.00

Phase 4: Unpost Payment In

Handler: UnpostPaymentInCommandHandler

Action: Fully reverses a posted payment — removes the journal, bank transaction, and reconciliations. Returns to Draft.

Prerequisites Check

CheckRule
Status = PostedCannot unpost a Draft payment
Open financial periodPaymentInDate period must still be open
Journal reversibleThe linked journal must not already be reversed
Reconciliations reversibleAny reconciled invoices must be in open periods

Tables Affected

TableOperationNotes
PaymentInHeaderUPDATEStatus → Draft, JournalId/JournalCode → NULL
JournalEntrySoft DELETE / ReversedJournal marked as reversed
BankTransactionHeaderSoft DELETEBank transaction removed
BankTransactionDetailSoft DELETEBank detail removed
SalesInvoiceReconciliationSoft DELETEReconciliation records removed
SalesInvoiceBalanceUPDATEDueBalance restored to original
SalesInvoiceHeaderUPDATEReconciledAmount, AmountToReconcile, IsFullyReconciled reset
PaymentInDetailUPDATEReconciledAmount → 0, AmountToReconcile restored
CustomerFinancialUPDATETotalPayments and OutstandingBalance reversed

Payment In with Commission (Cheque Payment)

When a payment method has a commission configured (e.g. 2% bank cheque commission), the journal has additional lines.

Example

json
{
  "paymentInDetails": [
    {
      "paidBy": "Customer",
      "paidByDetailsId": 433,
      "paymentMethodId": 3,
      "amount": 1150.00,
      "paymentMethodDetail": {
        "chequeNumber": "CHQ-001",
        "chequeDueDate": "2026-02-15",
        "commissionType": "Percent",
        "commissionValue": 2.0,
        "commissionAccountId": 6010,
        "allowVat": true,
        "vatRatio": 15.0,
        "vatAccountId": 2030
      }
    }
  ]
}

Commission Calculations

CommissionAmount = Amount × CommissionValue / 100 = 1150 × 2% = 23.00
VatAmount        = CommissionAmount × VatRatio / 100 = 23.00 × 15% = 3.45
NetAmount        = Amount - CommissionAmount - VatAmount = 1150 - 23 - 3.45 = 1123.55

Updated PaymentInDetail

ColumnValue
Amount1150.00
NetAmount1123.55
ReconciledAmount (available)1123.55

Journal Entry Lines (4 lines instead of 2)

JE-2026-0126 — Payment In (with Commission)

  DR  1020  Bank Account              1,123.55   ← net received
  DR  6010  Commission Expense           23.00   ← bank commission
  DR  2030  VAT Input (Commission)        3.45   ← VAT on commission
      CR  1010  Accounts Receivable           1,150.00   ← clears full invoice
                                     ---------  ---------
      Total                          1,150.00   1,150.00

Customer Advanced Payment

An advanced payment is received before any invoice exists. It is held as a liability (deferred revenue / customer deposit).

Key Rules

  • IsCustomerAdvancedPayment = true
  • Only one detail line is allowed
  • A Tax ID must be provided (for VAT on advances, if applicable)
  • PaidBy must be Customer
  • Cannot be reconciled at creation time — reconciled later when invoice is issued

Journal Entry Lines

JE-2026-0127 — Customer Advanced Payment

  DR  1020  Bank Account              1,150.00
      CR  2040  Customer Advances              1,150.00   ← liability account

The AccountId used for the credit line comes from the payment header's AccountId field (the configured advance/deposit GL account), not from the customer's receivable account.

Reconciliation at Invoice Time

When a sales invoice is later issued and linked to this advance:

  • SalesInvoiceReconciliation record created
  • Customer advance balance reduced
  • AmountToReconcile on the PaymentInDetail decremented

Treasury Payment (Cash)

When PaymentHub = Treasury, the flow is identical to Bank but creates a TreasuryTransaction instead of a BankTransaction.

Differences

PropertyBankTreasury
PaymentHubBankTreasury
PaymentHubDetailIdBankAccountIdTreasuryId
Transaction createdBankTransactionHeader/DetailTreasuryTransactionHeader/Detail
GL debit accountBankAccount.GLAccountIdTreasury.GLAccountId

Journal Entry Lines (Treasury Cash)

JE-2026-0128 — Cash Payment In

  DR  1001  Petty Cash / Treasury     1,150.00
      CR  1010  Accounts Receivable           1,150.00

Payment Method Types Reference

TypeCommissionDataChequeFieldsNotes
CashOptionalNoPhysical cash received
CheckOptionalRequired (ChequeNumber + ChequeDueDate)Post-dated cheques supported
VisaOptionalNoCard payment, commission = merchant fee
MasterCardOptionalNoCard payment
SPAN / MadaOptionalNoLocal debit network
TransferOptionalNoBank wire transfer, BankReference used

Multi-Currency Payment In

When a customer pays in a foreign currency (e.g. USD), amounts are stored in both currencies.

Example — USD Payment at 3.75 SAR/USD

json
{
  "currencyId": 1,
  "rate": 3.75,
  "paymentInDetails": [
    {
      "amount": 1000.00,
      "currencyId": 1,
      "rate": 3.75
    }
  ]
}

Stored Values

ColumnHeaderDetail
Amount1000.00 USD1000.00 USD
LocalAmount3750.00 SAR3750.00 SAR
NetAmount1000.00 USD1000.00 USD
NetLocalAmount3750.00 SAR3750.00 SAR

Journal Entry Lines

JE-2026-0129 — Payment In (USD)

  DR  1020  Bank Account              3,750.00 SAR   (= 1000 USD × 3.75)
      CR  1010  Accounts Receivable           3,750.00 SAR

All GL postings use local (base) currency amounts. Foreign amounts are stored for reference only.


Complete Transaction Flow Summary

1. User submits Add Payment In request

2. AddPaymentInCommandHandler.Handle()

3. Validate: payment date, hub, currency, customer, payment method,
             commission fields, cheque fields, cost center sums

4. GetCurrentPeriodQuery(PaymentInDate) → FinancialYearPeriodId

5. Generate sequence code → "PI-2026-0001"

6. Calculate detail amounts:
   - LocalAmount    = 1150 × 1.0 = 1150
   - CommissionAmount = 0
   - VatAmount       = 0
   - NetAmount       = 1150
   - NetLocalAmount  = 1150

7. INSERT PaymentInHeader (Status = Draft)
   INSERT PaymentInDetail × 1
   INSERT PaymentInMethodDetail × 1

8. SaveChanges → committed

9. Return PaymentInHeaderId

--- DRAFT PHASE COMPLETE ---

10. User clicks "Post"

11. PostPaymentInCommandHandler.Handle()

12. Validate: Draft status, open period, GL accounts configured

13. Build Journal command:
    DR  Bank GL Account   1150
        CR  Customer AR Account    1150

14. Call IAccountingPublicApi.AddJournal() → JournalCreatedDto

15. Create BankTransactionHeader + BankTransactionDetail

16. UPDATE PaymentInHeader:
    Status = Posted
    JournalId = [GUID]
    JournalCode = "JE-2026-0125"

17. (If auto-reconcile enabled)
    INSERT SalesInvoiceReconciliation
    UPDATE SalesInvoiceBalance (DueBalance = 0)
    UPDATE SalesInvoiceHeader (IsFullyReconciled = true)
    UPDATE PaymentInDetail (ReconciledAmount = 1150)

18. UPDATE CustomerFinancial:
    TotalPayments += 1150
    OutstandingBalance -= 1150

19. SaveChanges → committed

20. Publish webhook event (reconciliation, if enabled)

21. Return PaymentInHeaderId

--- POST PHASE COMPLETE ---

22. (Optional) User clicks "Unpost"

23. UnpostPaymentInCommandHandler.Handle()

24. Validate: Posted, open period, journal reversible, reconciliation periods open

25. Soft DELETE SalesInvoiceReconciliation records
    Restore SalesInvoiceBalance.DueBalance
    Reset SalesInvoiceHeader.IsFullyReconciled
    Reset PaymentInDetail.ReconciledAmount

26. Soft DELETE BankTransactionHeader / BankTransactionDetail

27. Reverse or soft delete JournalEntry

28. UPDATE PaymentInHeader: Status = Draft, JournalId/JournalCode = NULL

29. Reverse CustomerFinancial changes

30. SaveChanges → committed

--- UNPOST PHASE COMPLETE ---

Database Transactions

Add Phase

sql
BEGIN TRANSACTION

  INSERT INTO PaymentInHeader VALUES (...)       -- Status = Draft
  INSERT INTO PaymentInDetail VALUES (...)       -- 1 detail
  INSERT INTO PaymentInMethodDetail VALUES (...)  -- Method detail

COMMIT TRANSACTION

Duration: ~40–80ms

Post Phase

sql
BEGIN TRANSACTION

  -- Step 1: Create journal (via Accounting public API)
  INSERT INTO JournalEntry VALUES (...)          -- Type = PaymentIn, Posted
  INSERT INTO JournalEntryLine VALUES (...)      -- 2 lines (Bank DR + AR CR)

  -- Step 2: Create bank transaction
  INSERT INTO BankTransactionHeader VALUES (...)
  INSERT INTO BankTransactionDetail VALUES (...)

  -- Step 3: Reconcile invoice (if enabled)
  INSERT INTO SalesInvoiceReconciliation VALUES (...)
  UPDATE SalesInvoiceBalance SET DueBalance = 0 ...
  UPDATE SalesInvoiceHeader SET IsFullyReconciled = 1 ...
  UPDATE PaymentInDetail SET ReconciledAmount = 1150 ...

  -- Step 4: Update payment header
  UPDATE PaymentInHeader SET Status = 'Posted', JournalId = @JournalId ...

  -- Step 5: Update customer
  UPDATE CustomerFinancial SET TotalPayments += 1150, OutstandingBalance -= 1150 ...

COMMIT TRANSACTION

Duration: ~150–400ms


Error Scenarios

Add / Edit Validation Failures

Error ConditionError MessageResolution
Closed financial period"Payment date must be in an open financial period"Change date or open period
Missing PaymentHubDetailId"PaymentHubDetailId is required"Provide the BankAccountId (hub=Bank) or TreasuryId (hub=Treasury)
Missing cheque data"Cheque number and due date are required for cheque payments"Fill cheque fields
Advanced payment — multiple details"Customer advanced payment can only have one detail line"Reduce to single detail
Advanced payment — missing tax"Tax definition required for customer advanced payment"Set TaxId on header
Cost center sum ≠ 100%"Cost center allocations must total 100%"Adjust percentages
Amount ≤ 0"Payment amount must be greater than zero"Correct amount

Post Validation Failures

Error ConditionError MessageResolution
Not Draft"Payment must be in Draft status to post"Already posted
Missing customer GL account"Customer receivable account not configured"Configure customer accounting
Missing payment method GL"Payment method GL account not configured"Configure method account
Missing commission GL"Commission account required for payment method with commission"Set CommissionAccountId
Closed period"Cannot post in a closed financial period"Reopen period

Unpost Validation Failures

Error ConditionError MessageResolution
Not Posted"Payment must be Posted to unpost"Nothing to unpost
Closed period"Payment period is closed — cannot unpost"Reopen period
Journal already reversed"Journal entry has already been reversed"Cannot reverse twice
Reconciliation in closed period"Reconciled invoice is in a closed period"Reopen the invoice's period

Key Interfaces Used

InterfaceUsage
IAppsUnitOfWorkRepository access for all ERP entities
ISecurityServiceCurrent user, tenant, branch, company context
IClockServiceTestable timestamp provider
IGeneralSettingsPublicApiSequence number generation, current branch/company, financial period
IAccountingPublicApiCreates Journal Entries for posted payments
IPaymentInProcessingServiceEncapsulates payment creation, posting, journal building, commission logic

Payment In vs Payment Out

PropertyPayment InPayment Out
DirectionMoney receivedMoney sent
Typical payerCustomerVendor
Bank line DR/CRDR BankCR Bank
AR/AP line DR/CRCR Accounts ReceivableDR Accounts Payable
Reconciles withSales InvoicesPurchase Invoices
Advanced paymentCustomer Advance (liability)Vendor Advance (asset)

Document Version: 1.0
Namespace: AppsPortal.Application.Finance.PaymentIn
Example Date: 2026-01-28
Currency: Saudi Riyal (SAR)
Total Payment: 1,150.00 SAR

Internal Documentation — Microtec