{
  "feature": "payment-processing",
  "version": "1.0.0",
  "description": "Process incoming, outgoing, and internal transfer payments with multi-currency support, reference allocation, and automatic reconciliation",
  "category": "payment",
  "tags": [
    "accounting",
    "payments",
    "reconciliation",
    "multi-currency",
    "erp"
  ],
  "fields": [
    {
      "name": "payment_type",
      "type": "select",
      "required": true,
      "options": [
        {
          "value": "receive",
          "label": "Receive"
        },
        {
          "value": "pay",
          "label": "Pay"
        },
        {
          "value": "internal_transfer",
          "label": "Internal Transfer"
        }
      ],
      "label": "Payment Type"
    },
    {
      "name": "party_type",
      "type": "select",
      "required": false,
      "options": [
        {
          "value": "customer",
          "label": "Customer"
        },
        {
          "value": "supplier",
          "label": "Supplier"
        },
        {
          "value": "employee",
          "label": "Employee"
        },
        {
          "value": "shareholder",
          "label": "Shareholder"
        }
      ],
      "label": "Party Type"
    },
    {
      "name": "party",
      "type": "text",
      "required": false,
      "label": "Party"
    },
    {
      "name": "paid_from",
      "type": "text",
      "required": true,
      "validation": [
        {
          "type": "minLength",
          "value": 1,
          "message": "Source account must be specified"
        }
      ],
      "label": "Paid From"
    },
    {
      "name": "paid_to",
      "type": "text",
      "required": true,
      "validation": [
        {
          "type": "minLength",
          "value": 1,
          "message": "Target account must be specified"
        }
      ],
      "label": "Paid To"
    },
    {
      "name": "paid_amount",
      "type": "number",
      "required": true,
      "validation": [
        {
          "type": "min",
          "value": 0,
          "message": "Paid amount must be greater than zero"
        }
      ],
      "label": "Paid Amount"
    },
    {
      "name": "received_amount",
      "type": "number",
      "required": true,
      "validation": [
        {
          "type": "min",
          "value": 0,
          "message": "Received amount must be greater than zero"
        }
      ],
      "label": "Received Amount"
    },
    {
      "name": "source_exchange_rate",
      "type": "number",
      "required": true,
      "validation": [
        {
          "type": "min",
          "value": 0,
          "message": "Source exchange rate must be greater than zero"
        }
      ],
      "label": "Source Exchange Rate"
    },
    {
      "name": "target_exchange_rate",
      "type": "number",
      "required": true,
      "validation": [
        {
          "type": "min",
          "value": 0,
          "message": "Target exchange rate must be greater than zero"
        }
      ],
      "label": "Target Exchange Rate"
    },
    {
      "name": "references",
      "type": "json",
      "required": false,
      "label": "References"
    },
    {
      "name": "mode_of_payment",
      "type": "select",
      "required": false,
      "options": [
        {
          "value": "cash",
          "label": "Cash"
        },
        {
          "value": "bank_transfer",
          "label": "Bank Transfer"
        },
        {
          "value": "cheque",
          "label": "Cheque"
        },
        {
          "value": "wire_transfer",
          "label": "Wire Transfer"
        },
        {
          "value": "credit_card",
          "label": "Credit Card"
        },
        {
          "value": "online_payment",
          "label": "Online Payment"
        }
      ],
      "label": "Mode Of Payment"
    },
    {
      "name": "status",
      "type": "select",
      "required": true,
      "options": [
        {
          "value": "draft",
          "label": "Draft"
        },
        {
          "value": "submitted",
          "label": "Submitted"
        },
        {
          "value": "cancelled",
          "label": "Cancelled"
        }
      ],
      "label": "Status"
    }
  ],
  "actors": [
    {
      "id": "accounts_user",
      "name": "Accounts User",
      "type": "human",
      "description": "Creates and submits payment entries"
    },
    {
      "id": "accounting_system",
      "name": "Accounting System",
      "type": "system",
      "description": "Posts GL entries, updates outstanding balances, and reconciles"
    }
  ],
  "states": {
    "field": "status",
    "values": [
      {
        "name": "draft",
        "description": "Payment entry is being prepared",
        "initial": true
      },
      {
        "name": "submitted",
        "description": "Payment posted to the ledger"
      },
      {
        "name": "cancelled",
        "description": "Payment reversed",
        "terminal": true
      }
    ],
    "transitions": [
      {
        "from": "draft",
        "to": "submitted",
        "actor": "accounts_user",
        "description": "Submit payment entry for posting"
      },
      {
        "from": "submitted",
        "to": "cancelled",
        "actor": "accounts_user",
        "description": "Cancel payment and reverse GL entries"
      }
    ]
  },
  "rules": {
    "balanced_entries": {
      "description": "Total debit must equal total credit in the GL entries generated by the payment.\n"
    },
    "allocation_limit": {
      "description": "Allocated amount against a reference cannot exceed that reference outstanding amount.\n"
    },
    "reference_validation": {
      "description": "Referenced documents must be in Submitted status before allocation. Draft or cancelled documents cannot be referenced.\n"
    },
    "exchange_rate_auto": {
      "description": "Exchange rates are auto-fetched for the posting date when source and target currencies differ.\n"
    },
    "party_required": {
      "description": "Party type and party are required for Receive and Pay payment types. Internal Transfers do not require a party.\n"
    },
    "internal_transfer_accounts": {
      "description": "Internal Transfer requires different paid_from and paid_to accounts. Same-account transfers are rejected.\n"
    },
    "unallocated_tracking": {
      "description": "Unallocated amount is tracked when payment exceeds total allocated references. Can be allocated later.\n"
    },
    "cancellation_reversal": {
      "description": "Cancellation reverses all GL entries and restores outstanding on referenced documents.\n"
    }
  },
  "outcomes": {
    "process_payment": {
      "given": [
        "payment entry is in Draft status",
        {
          "field": "paid_amount",
          "operator": "gt",
          "value": 0,
          "description": "Paid amount is positive"
        },
        {
          "field": "paid_from",
          "operator": "exists",
          "description": "Source account is specified"
        },
        {
          "field": "paid_to",
          "operator": "exists",
          "description": "Target account is specified"
        }
      ],
      "then": [
        {
          "action": "transition_state",
          "field": "status",
          "from": "draft",
          "to": "submitted"
        },
        {
          "action": "create_record",
          "type": "gl_entry",
          "target": "gl_entries",
          "description": "Create debit and credit GL entries for the payment"
        },
        {
          "action": "emit_event",
          "event": "payment.submitted",
          "payload": [
            "payment_id",
            "payment_type",
            "party",
            "paid_amount",
            "received_amount"
          ]
        }
      ],
      "result": "Payment is submitted with GL entries posted and referenced document outstanding amounts reduced",
      "transaction": true,
      "priority": 10
    },
    "reconcile_payment": {
      "given": [
        "payment is in Submitted status",
        {
          "field": "references",
          "operator": "exists",
          "description": "At least one reference document is allocated"
        }
      ],
      "then": [
        {
          "action": "set_field",
          "target": "unallocated_amount",
          "description": "Calculated as paid_amount minus sum of all allocated amounts"
        },
        {
          "action": "emit_event",
          "event": "payment.reconciled",
          "payload": [
            "payment_id",
            "references",
            "unallocated_amount"
          ]
        }
      ],
      "result": "Payment is reconciled against referenced invoices with outstanding amounts updated",
      "priority": 11
    },
    "cancel_payment": {
      "given": [
        "payment is in Submitted status"
      ],
      "then": [
        {
          "action": "transition_state",
          "field": "status",
          "from": "submitted",
          "to": "cancelled"
        },
        {
          "action": "create_record",
          "type": "gl_entry",
          "target": "gl_entries",
          "description": "Reverse all GL entries for this payment"
        },
        {
          "action": "emit_event",
          "event": "payment.cancelled",
          "payload": [
            "payment_id",
            "payment_type",
            "party",
            "paid_amount"
          ]
        }
      ],
      "result": "Payment is cancelled, GL entries reversed, and outstanding on referenced documents restored",
      "transaction": true,
      "priority": 12
    }
  },
  "errors": [
    {
      "code": "PAYMENT_ALLOCATION_EXCEEDED",
      "message": "Allocated amount exceeds outstanding amount on the referenced document.",
      "status": 400
    },
    {
      "code": "PAYMENT_REFERENCE_INVALID",
      "message": "Referenced document does not exist or is not in a submitted state.",
      "status": 400
    },
    {
      "code": "PAYMENT_BALANCE_MISMATCH",
      "message": "Total debit does not equal total credit in the payment GL entries.",
      "status": 500
    }
  ],
  "events": [
    {
      "name": "payment.submitted",
      "description": "Payment entry transitions from Draft to Submitted",
      "payload": [
        "payment_id",
        "payment_type",
        "party",
        "paid_amount",
        "received_amount"
      ]
    },
    {
      "name": "payment.cancelled",
      "description": "Payment entry is cancelled and GL entries reversed",
      "payload": [
        "payment_id",
        "payment_type",
        "party",
        "paid_amount"
      ]
    },
    {
      "name": "payment.reconciled",
      "description": "Payment is reconciled against one or more references",
      "payload": [
        "payment_id",
        "references",
        "unallocated_amount"
      ]
    }
  ],
  "related": [
    {
      "feature": "sales-purchase-invoicing",
      "type": "required",
      "reason": "Payments are allocated against sales and purchase invoices"
    },
    {
      "feature": "general-ledger",
      "type": "required",
      "reason": "Payment submission creates GL entries"
    },
    {
      "feature": "bank-reconciliation",
      "type": "recommended",
      "reason": "Bank statements are matched against payment entries"
    }
  ],
  "agi": {
    "goals": [
      {
        "id": "reliable_payment_processing",
        "description": "Process incoming, outgoing, and internal transfer payments with multi-currency support, reference allocation, and automatic reconciliation",
        "success_metrics": [
          {
            "metric": "policy_violation_rate",
            "target": "0%",
            "measurement": "Operations that violate defined policies"
          },
          {
            "metric": "audit_completeness",
            "target": "100%",
            "measurement": "All decisions have complete audit trails"
          }
        ],
        "constraints": [
          {
            "type": "regulatory",
            "description": "All operations must be auditable and traceable",
            "negotiable": false
          }
        ]
      }
    ],
    "autonomy": {
      "level": "supervised",
      "human_checkpoints": [
        "before transitioning to a terminal state"
      ],
      "escalation_triggers": [
        "error_rate > 5",
        "consecutive_failures > 3"
      ]
    },
    "safety": {
      "action_permissions": [
        {
          "action": "process_payment",
          "permission": "autonomous"
        },
        {
          "action": "reconcile_payment",
          "permission": "autonomous"
        },
        {
          "action": "cancel_payment",
          "permission": "supervised"
        }
      ]
    },
    "tradeoffs": [
      {
        "prefer": "accuracy",
        "over": "speed",
        "reason": "financial transactions must be precise and auditable"
      }
    ],
    "verification": {
      "invariants": [
        "error messages never expose internal system details",
        "state transitions follow the defined state machine — no illegal transitions"
      ]
    },
    "coordination": {
      "protocol": "orchestrated",
      "consumes": [
        {
          "capability": "sales_purchase_invoicing",
          "from": "sales-purchase-invoicing",
          "fallback": "fail"
        },
        {
          "capability": "general_ledger",
          "from": "general-ledger",
          "fallback": "fail"
        }
      ]
    }
  },
  "extensions": {
    "source": {
      "repo": "https://github.com/frappe/erpnext",
      "project": "ERPNext",
      "tech_stack": "Python, Frappe Framework, MariaDB/PostgreSQL"
    }
  }
}