feat(api): support idempotent valuation writes (#1637)

* feat(api): support idempotent valuation writes

* fix(api): clarify valuation upsert status

* docs(api): document nested valuation upserts

* docs(api): clarify valuation upsert semantics

* docs(api): clarify valuation upsert signaling
This commit is contained in:
ghost
2026-05-04 10:51:48 -06:00
committed by GitHub
parent ddaf42c96c
commit 05ef8bd9e7
4 changed files with 133 additions and 2 deletions

View File

@@ -4,6 +4,7 @@ class Api::V1::ValuationsController < Api::V1::BaseController
include Pagy::Backend
InvalidFilterError = Class.new(StandardError)
BOOLEAN_PARAM = ActiveModel::Type::Boolean.new
before_action :ensure_read_scope, only: [ :index, :show ]
before_action :ensure_write_scope, only: [ :create, :update ]
@@ -83,11 +84,17 @@ class Api::V1::ValuationsController < Api::V1::BaseController
end
account = current_resource_owner.family.accounts.find(valuation_account_id)
requested_upsert = upsert_requested?
existing_write = false
create_success = false
error_payload = nil
ActiveRecord::Base.transaction do
account.lock! if requested_upsert
existing_write = account.entries.valuations.exists?(date: valuation_params[:date]) if requested_upsert
# upsert=true only affects response status; reconciliation owns write behavior.
result = account.create_reconciliation(
balance: valuation_params[:amount],
date: valuation_params[:date]
@@ -124,7 +131,7 @@ class Api::V1::ValuationsController < Api::V1::BaseController
return
end
render :show, status: :created
render :show, status: requested_upsert && existing_write ? :ok : :created
rescue ActiveRecord::RecordNotFound
render json: {
@@ -289,4 +296,10 @@ class Api::V1::ValuationsController < Api::V1::BaseController
def valuation_params
params.require(:valuation).permit(:amount, :date, :notes)
end
def upsert_requested?
raw_value = params.key?(:upsert) ? params[:upsert] : params.dig(:valuation, :upsert)
BOOLEAN_PARAM.cast(raw_value)
end
end