Add business pricing and closure controls with compatible digest optimization

This commit is contained in:
Takeshi
2026-09-09 12:04:12 +09:00
parent 071e338e82
commit b3b82ef03e
35 changed files with 2203 additions and 59 deletions
+15 -5
View File
@@ -79,12 +79,15 @@ func _run() -> void:
var summaries: Array = _runtime.operations_coordinator.get_day_summaries()
_expect(summaries.size() == day and bool(summaries[-1].get(&"balanced", false)), "business day %d closes with a reconciled ledger" % day)
_expect(_state.get_resource(&"gold") >= 0, "day %d retains cash after real payroll and purchases" % day)
_expect(int(summaries[-1].get(&"arrears_total", -1)) == 0, "day %d pays all real wages without arrears" % day)
if day < 3:
_command(&"purchase_supplies", {&"warehouse_id": _ids[&"warehouse"], &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 40})
_expect(_sales(&"standard_room") > 0, "the same inn earns lodging revenue")
_expect(_sales(&"reception") == 0, "three days do not depend on artificial reception revenue")
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "three-day supply history remains restorable")
var evidence := {"checks": _checks, "failures": _failures, "meal_sales": _sales(&"cafeteria"), "lodging_sales": _sales(&"standard_room"), "raw_deliveries": _completed_deliveries(SupplyCatalog.RAW_FOOD), "meal_deliveries": _completed_deliveries(SupplyCatalog.BASIC_MEAL), "cash": _state.get_resource(&"gold"), "closes": _runtime.operations_coordinator.get_day_summaries(), "supply": _runtime.get_supply_management_report()}
var evidence_path := ProjectSettings.globalize_path("res://artifacts/supply-chain/normal-play-report.json")
var evidence_dir := "res://artifacts/business-management" if OS.get_environment("THE_TREE_BUSINESS_ACCEPTANCE") == "1" else "res://artifacts/supply-chain"
var evidence_path := ProjectSettings.globalize_path(evidence_dir.path_join("normal-play-report.json"))
DirAccess.make_dir_recursive_absolute(evidence_path.get_base_dir())
var file := FileAccess.open(evidence_path, FileAccess.WRITE)
if file != null:
@@ -194,9 +197,16 @@ func _start_preview() -> void:
if callback.get_method() in [&"_save_manual", &"_load_manual"]:
button.disabled = true
button.tooltip_text = "この試遊は保存しません。"
_main.call("_activate_management_mode", &"product")
var panel := _main.find_child("SupplyManagementPanel", true, false) as SupplyManagementPanel
panel.select_tab(&"kitchen")
_main.call("_set_status", "通常予算から育てた宿の試遊です。Spaceで再開し、商品タブで仕入れ・調理・配送を確認できます(保存なし)。", true, true)
if OS.get_environment("THE_TREE_BUSINESS_PREVIEW") == "1":
root.title = "The Tree · 料金と営業の試遊(保存なし)"
_main.call("_activate_management_mode", &"business")
var business := _main.find_child("BusinessManagementPanel", true, false)
business.call("select_facility", _ids[&"cafeteria"])
_main.call("_set_status", "料金と営業状態を変更できます。Spaceで再開すると、客の行動に反映されます(保存なし)。", true, true)
else:
_main.call("_activate_management_mode", &"product")
var panel := _main.find_child("SupplyManagementPanel", true, false) as SupplyManagementPanel
panel.select_tab(&"kitchen")
_main.call("_set_status", "通常予算から育てた宿の試遊です。Spaceで再開し、商品タブで仕入れ・調理・配送を確認できます(保存なし)。", true, true)
_clock.set_paused(true)
print("SUPPLY_PREVIEW_READY checks=%d failures=0" % _checks)
@@ -75,6 +75,8 @@ func _run() -> void:
_test_unavailable_and_expiry()
_test_restore_guards()
_test_pickup_retry()
_test_source_closes_after_assignment()
_test_source_closes_after_loading()
_test_unavailable_before_pickup()
_test_partial_expiry_return()
_test_shift_boundary()
@@ -202,6 +204,36 @@ func _test_pickup_retry() -> void:
_expect(_quantity(_inventory(_destination)) == 8 and _quantity(_cargo()) == 0, "retry delivers the same stock exactly once")
func _test_source_closes_after_assignment() -> void:
_expect(_runtime.restore_snapshot(_reserved), "restore source-closure approach scenario")
_clock.advance_minutes(1)
var old_task := _worker().current_task_id
_expect(_request().state == LogisticsRequest.State.ASSIGNED and not old_task.is_empty(), "source closure begins after assigning the real pickup Task")
_expect(_command(&"set_facility_policy", {&"facility_id": _source, &"patch": {&"business_open": false}}), "close the source while its porter approaches")
_wait_for(LogisticsRequest.State.BLOCKED, 40)
_expect(_request().state == LogisticsRequest.State.BLOCKED and _request().state_reason == "SOURCE_CLOSED", "arrival at a newly closed source blocks before loading")
_expect(_quantity(_inventory(_source)) == 8 and _quantity(_cargo()) == 0 and _quantity(_inventory(_destination)) == 0, "closed source retains every purchased unit without transfer")
_expect(_runtime.inventory_service.available_quantity(_inventory(_source), SupplyCatalog.RAW_FOOD) == 8 and _worker().current_task_id.is_empty(), "blocked pickup releases both source stock and employee reservations")
_expect(_runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "closed-source cleanup retains no dispatcher or Task ghost")
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "blocked closed-source state passes strict Runtime restore")
_expect(_command(&"set_facility_policy", {&"facility_id": _source, &"patch": {&"business_open": true}}), "reopen the source for a retry")
_wait_for(LogisticsRequest.State.DELIVERING, 40)
_expect(_request().state == LogisticsRequest.State.DELIVERING and _worker().current_task_id != old_task and _quantity(_cargo()) == 8, "reopening retries with a fresh Task and physical pickup")
var loaded_cell := _worker().current_cell
_wait_for(LogisticsRequest.State.COMPLETED, 40)
_expect(_request().state == LogisticsRequest.State.COMPLETED and _worker().current_cell != loaded_cell and _quantity(_inventory(_destination)) == 8, "reopened source stock reaches the kitchen by actual porter movement")
_expect(_quantity(_inventory(_source)) == 0 and _quantity(_cargo()) == 0 and _runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "reopened source delivery consumes and releases ownership exactly once")
func _test_source_closes_after_loading() -> void:
_expect(_runtime.restore_snapshot(_loaded), "restore loaded source-closure scenario")
_expect(_command(&"set_facility_policy", {&"facility_id": _source, &"patch": {&"business_open": false}}), "close the source after loading")
var cell := _worker().current_cell
_wait_for(LogisticsRequest.State.COMPLETED, 40)
_expect(_request().state == LogisticsRequest.State.COMPLETED and _worker().current_cell != cell and _quantity(_inventory(_destination)) == 8, "already-loaded porter can finish delivery to an open destination")
_expect(_quantity(_cargo()) == 0 and _runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "delivery after source closure clears cargo and carrier ownership")
func _test_unavailable_before_pickup() -> void:
_expect(_runtime.restore_snapshot(_reserved), "restore unloaded health failure")
_clock.advance_minutes(1)