RESTForge

POST /adjust

Spesifikasi endpoint adjust untuk increment atau decrement field numerik

Endpoint /adjust digunakan untuk melakukan operasi increment atau decrement secara atomik pada field numerik dalam satu record.

Referensi Cepat (Quick Reference)

PropertiNilai
MethodPOST
URL/api/{project}/{endpoint}/adjust
Content-Typeapplication/json
Status Sukses200 OK
DatabasePostgreSQL, MySQL, Oracle
CacheInvalidasi otomatis setelah adjust berhasil
Distributed LockWRITE lock per-record (jika diaktifkan)
Event LifecycleonBeforeAdjust → ADJUST → onAfterAdjust

Ikhtisar (Overview)

Berbeda dengan endpoint /update yang meng-overwrite nilai field secara absolut (SET stock = 90), endpoint /adjust menggunakan operasi aritmetika di level SQL (SET stock = stock + N). Pendekatan ini bersifat atomik sehingga aman dari race condition ketika beberapa request secara bersamaan mengubah field yang sama.

Request body wajib menyertakan primary key untuk mengidentifikasi record target dan array adjustments berisi satu atau lebih operasi adjustment. Setiap adjustment menentukan field yang akan diubah, delta value (positif untuk increment, negatif untuk decrement), serta opsional reason sebagai catatan alasan perubahan.

Endpoint ini dilengkapi mekanisme guard clause di level SQL yang mencegah nilai field turun di bawah batas minimum. Jika guard clause terlanggar, server mengembalikan 409 Conflict tanpa melakukan perubahan apapun.

Format Request (Request Format)

Parameter (Parameters)

ParameterTipeWajibKeterangan
{primaryKey}stringYaPrimary key record yang akan di-adjust
adjustmentsarrayYaArray minimal 1 item berisi operasi adjustment
adjustments[].fieldstringYaNama field numerik yang akan di-adjust
adjustments[].valuenumberYaDelta value; positif = increment, negatif = decrement
adjustments[].reasonstringTidakAlasan perubahan (wajib jika reasonRequired: true di konfigurasi)

Contoh Request (Request Examples)

Decrement stock (pengurangan):

POST /api/mini-inventory/item-product/adjust
{
    "item_product_id": "550e8400-e29b-41d4-a716-446655440000",
    "adjustments": [
        {
            "field": "stock",
            "value": -5,
            "reason": "Penjualan harian"
        }
    ]
}

Increment stock (penambahan):

POST /api/mini-inventory/item-product/adjust
{
    "item_product_id": "550e8400-e29b-41d4-a716-446655440000",
    "adjustments": [
        {
            "field": "stock",
            "value": 20,
            "reason": "Restok dari supplier"
        }
    ]
}

Multi-field adjustment:

POST /api/mini-inventory/item-product/adjust
{
    "item_product_id": "550e8400-e29b-41d4-a716-446655440000",
    "adjustments": [
        {
            "field": "stock",
            "value": -3,
            "reason": "Penjualan"
        },
        {
            "field": "reserved_qty",
            "value": 3,
            "reason": "Reservasi untuk order ORD-2026-0042"
        }
    ]
}

Body Options

Endpoint /adjust mendukung format request body alternatif {data, options} untuk mengirimkan opsi tambahan yang dapat dibaca oleh component handler dan processor. Detail lengkap tersedia di halaman Body Options.

POST /api/mini-inventory/item-product/adjust
{
    "data": {
        "item_product_id": "550e8400-e29b-41d4-a716-446655440000",
        "adjustments": [
            {
                "field": "stock",
                "value": -5,
                "reason": "Penjualan harian"
            }
        ]
    },
    "options": {
        "notify_warehouse": true
    }
}

Format Response (Response Format)

Response Sukses (Success Response)

HTTP 200 OK

{
    "success": true,
    "message": "item_product data successfully adjusted",
    "data": {
        "item_product_id": "550e8400-e29b-41d4-a716-446655440000",
        "item_code": "ITM-001",
        "item_name": "Keyboard Mechanical RGB",
        "stock": 95,
        "reserved_qty": 3,
        "updated_at": "2026-04-16T10:30:00.000Z",
        "updated_by": "Input from API"
    },
    "timestamp": "2026-04-16T10:30:00.000Z"
}

Response Error (Error Responses)

400 — Payload kosong:

{
    "success": false,
    "error": "Invalid payload",
    "message": "Payload cannot be empty",
    "timestamp": "2026-04-16T10:30:00.000Z"
}

400 — Primary key tidak dikirim:

{
    "success": false,
    "error": "Invalid payload",
    "message": "Primary key is required for adjust operation",
    "timestamp": "2026-04-16T10:30:00.000Z"
}

400 — Adjustments tidak valid:

{
    "success": false,
    "error": "Invalid payload",
    "message": "Adjustments must be a non-empty array",
    "timestamp": "2026-04-16T10:30:00.000Z"
}

400 — Field tidak dikonfigurasi untuk adjust:

{
    "success": false,
    "error": "Invalid payload",
    "message": "Field 'item_name' is not configured for adjustment",
    "timestamp": "2026-04-16T10:30:00.000Z"
}

404 — Record tidak ditemukan:

{
    "success": false,
    "error": "Not found",
    "message": "item_product data not found",
    "timestamp": "2026-04-16T10:30:00.000Z"
}

409 — Guard clause terlanggar:

{
    "success": false,
    "error": "Constraint violation",
    "message": "Adjustment would result in value below minimum for field 'stock'",
    "timestamp": "2026-04-16T10:30:00.000Z"
}

500 — Internal server error:

{
    "success": false,
    "error": "Internal server error",
    "message": "An unexpected error occurred",
    "timestamp": "2026-04-16T10:30:00.000Z"
}

Guard Clause

Endpoint /adjust menerapkan guard clause di level SQL untuk mencegah field numerik turun di bawah batas minimum yang dikonfigurasi. Mekanisme ini diimplementasikan sebagai kondisi WHERE dalam statement UPDATE:

UPDATE item_product
SET stock = stock + (-5)
WHERE item_product_id = '550e8400...'
  AND (stock + (-5)) >= 0

Jika kondisi WHERE tidak terpenuhi (misalnya stock saat ini bernilai 3 tetapi diminta decrement 5), maka tidak ada row yang ter-update. Server mendeteksi kondisi ini dan mengembalikan 409 Conflict.

Guard clause berjalan sepenuhnya di level database, sehingga aman dari race condition meskipun beberapa request adjust diproses secara bersamaan pada record yang sama.

Konfigurasi (Configuration)

Perilaku endpoint /adjust dikontrol melalui objek adjustConfig dalam konfigurasi payload. Objek ini menentukan field mana saja yang dapat di-adjust beserta constraint masing-masing.

Contoh adjustConfig di payload
{
    "adjustConfig": {
        "reasonRequired": true,
        "fields": {
            "stock": {
                "type": "integer",
                "min": 0,
                "allowNegativeResult": false
            },
            "reserved_qty": {
                "type": "integer",
                "min": 0,
                "allowNegativeResult": false
            }
        }
    }
}
PropertiTipeKeterangan
reasonRequiredbooleanJika true, setiap item adjustment wajib menyertakan field reason
fieldsobjectMapping nama field ke konfigurasi constraint
fields.{name}.typestringTipe data field (integer, decimal, dll.)
fields.{name}.minnumberNilai minimum yang diperbolehkan setelah adjustment
fields.{name}.allowNegativeResultbooleanJika false, guard clause mencegah hasil adjustment bernilai negatif

Hanya field yang terdaftar di adjustConfig.fields yang dapat di-adjust. Request terhadap field yang tidak terdaftar akan menghasilkan error 400.

Perbandingan dengan /update (Comparison with /update)

Aspek/adjust/update
Operasi SQLSET stock = stock + N (relatif)SET stock = 90 (absolut)
AtomisitasAtomik di level databaseTidak atomik terhadap nilai saat ini
Race ConditionAman dari race conditionRentan race condition pada concurrent write
Guard ClauseDidukung (batas minimum via WHERE)Tidak tersedia
Kasus PenggunaanStok, saldo, counter, kuotaUpdate field umum (nama, status, alamat)

Untuk field numerik yang sering diubah secara bersamaan (concurrent), gunakan /adjust daripada /update. Operasi /update yang absolut dapat menyebabkan kehilangan data jika dua request membaca nilai yang sama lalu meng-overwrite satu sama lain.

Perilaku Cache (Cache Behavior)

Setelah operasi adjust berhasil, seluruh cache terkait endpoint ini di-invalidasi secara otomatis. Hal ini memastikan endpoint /read, /datatables, dan /lookup mengembalikan data terbaru pada request berikutnya.

Distributed Lock

Jika fitur distributed lock diaktifkan, endpoint /adjust mengakuisisi WRITE lock pada level record sebelum menjalankan operasi. Lock ini mencegah operasi tulis lain (adjust, update, delete) pada record yang sama berjalan secara bersamaan, sehingga menjamin konsistensi (consistency) data pada skenario high-concurrency.

Lock dilepaskan secara otomatis setelah operasi selesai, baik berhasil maupun gagal.

Event Lifecycle

Jika component engine dikonfigurasi di payload, endpoint /adjust menjalankan hook berikut:

onBeforeAdjust → ADJUST di database → onAfterAdjust

Hook onBeforeAdjust dapat memodifikasi data adjustment sebelum dieksekusi (misalnya menambah field reason secara otomatis atau memvalidasi logika bisnis tambahan). Hook onAfterAdjust dapat menjalankan side effect setelah adjustment berhasil (misalnya mengirim notifikasi stok rendah atau mencatat log audit).

Langkah Selanjutnya (Next Steps)

On this page