P05-02: 全費目と資金区分:表金・裏金、維持費未払い、仕入れ、人件費、元本、利息、税の帳簿への接続(原 P05-02 の完了の条件)
This commit is contained in:
@@ -42,6 +42,7 @@ func _run() -> void:
|
||||
_test_operation_top_ups_and_day_total()
|
||||
_test_legacy_midnight_top_up()
|
||||
_test_tax_arrears_next_day()
|
||||
_test_ledger_repayment_uses_hidden_funds()
|
||||
await _test_ledger_opened_from_main()
|
||||
await process_frame
|
||||
if _failures == 0:
|
||||
@@ -599,6 +600,14 @@ func _test_operation_top_ups_and_day_total() -> void:
|
||||
_expect(int(funds.get(&"fund_report_version", -1)) == 2, "the report carries its definition version")
|
||||
_expect(economy.get_balance(BACK) == 1000 - total and economy.get_balance(FRONT) == 0, "hidden funds fell by exactly the day's top-ups")
|
||||
_expect(_closed_ledger_text(runtime, clock).contains("裏金から表金へ補填 %dG" % total), "the ledger's close shows the day's every top-up")
|
||||
# Construction is outside A09: with no front funds it is refused and the hidden fund is not used.
|
||||
var refused: CommandResult = runtime.submit_command(&"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(4, 1, 0)})
|
||||
var top_ups_after := 0
|
||||
for entry: LedgerEntry in economy.get_entries():
|
||||
if entry.category == FinancePolicy.TOP_UP_CATEGORY:
|
||||
top_ups_after += entry.amount
|
||||
_expect(not refused.is_success() and economy.get_balance(BACK) == 1000 - total and top_ups_after == total,
|
||||
"A09 does not cover construction: refused with front 0, hidden funds untouched (%s)" % refused.details.get(&"reason", refused.message))
|
||||
var saved: Dictionary = runtime.create_snapshot()
|
||||
_expect(runtime.restore_snapshot(saved) and var_to_bytes(saved) == var_to_bytes(runtime.create_snapshot()), "the day with three top-ups restores exactly")
|
||||
# A report saved before the mark (back_top_up = the close's own top-up only) loads by that definition.
|
||||
@@ -682,17 +691,80 @@ func _test_tax_arrears_next_day() -> void:
|
||||
var funds1 := _day_funds(runtime, 1)
|
||||
_expect(int(funds1.get(&"rank_tax", -1)) == 20 and int(funds1.get(&"rank_tax_paid", -1)) == 0 and int(funds1.get(&"rank_tax_arrears", -1)) == 20, "A09: the unpaid tax carries over")
|
||||
_expect(int(runtime.operations_coordinator.get_day_summary(1)[&"settlement"][&"arrears_total"]) == 20 and int(runtime.get_operations_report().get(&"arrears_total", -1)) == 20, "the arrears include the tax")
|
||||
# F7 with arrears: the ledger shows the unpaid tax in the close and in today's cash section.
|
||||
var panel := OperatingLedgerPanel.new()
|
||||
root.add_child(panel)
|
||||
panel.setup(runtime, fixture[&"clock"])
|
||||
panel.select_latest_close()
|
||||
_expect(panel._closed_label.text.contains("未払い 税 20G・利息 0G") and panel._cash_label.text.contains("(未払い 20G)"), "the ledger shows the unpaid tax")
|
||||
panel.queue_free()
|
||||
# The closed day's arrears_total includes the tax arrears, so the Operations gate holds
|
||||
# construction and investment until they are paid.
|
||||
var blocked: CommandResult = runtime.submit_command(&"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(4, 1, 0)})
|
||||
_expect(not blocked.is_success() and StringName(blocked.details.get(&"reason", &"")) == &"ARREARS_REMAIN" and int(blocked.details.get(&"arrears_total", -1)) == 20,
|
||||
"tax arrears stop construction (ARREARS_REMAIN, arrears 20)")
|
||||
_advance_to(fixture, 1440 + 600)
|
||||
_expect(_sale(fixture, FRONT_SALES, FRONT, 100, "tax.d2"), "day 2 sale 100")
|
||||
_advance_to(fixture, 2880)
|
||||
var funds2 := _day_funds(runtime, 2)
|
||||
_expect(int(funds2.get(&"rank_tax", -1)) == 10 and int(funds2.get(&"rank_tax_paid", -1)) == 30 and int(funds2.get(&"rank_tax_arrears", -1)) == 0, "day 2 pays the older 20 and the new 10")
|
||||
_expect(economy.get_balance(FRONT) == 70 and economy.get_balance(FinancePolicy.RANK_TAX_PAYABLE) == 0, "front 70, no tax payable left")
|
||||
var built: CommandResult = runtime.submit_command(&"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(4, 1, 0)})
|
||||
_expect(built.is_success() and economy.get_balance(FRONT) == 50, "once the tax is paid, construction is allowed again (20 from front funds)")
|
||||
var saved: Dictionary = runtime.create_snapshot()
|
||||
_expect(runtime.restore_snapshot(saved) and var_to_bytes(saved) == var_to_bytes(runtime.create_snapshot()), "the arrears days restore exactly")
|
||||
_free_fixture(fixture)
|
||||
|
||||
|
||||
# F2 through the ordinary ledger: the panel's repayment controls cap by front + hidden
|
||||
# funds (A09), and a specified or full repayment that front funds cannot pay is one
|
||||
# transaction: the front fund pays first and the hidden fund covers the rest.
|
||||
func _test_ledger_repayment_uses_hidden_funds() -> void:
|
||||
var fixture := _new_fixture(5035)
|
||||
var runtime: Variant = fixture[&"runtime"]
|
||||
var clock: Variant = fixture[&"clock"]
|
||||
var economy: Variant = runtime.economy_service
|
||||
_advance_to(fixture, 420)
|
||||
_expect(_move(fixture, LOAN, FRONT, 1000, &"LOAN_PRINCIPAL_BORROWED", "panel.borrow"), "fixture principal 1000")
|
||||
_expect(_move(fixture, FRONT, &"OPERATING_EXPENSE", economy.get_balance(FRONT) - 20, &"OPERATING_EXPENSE", "panel.drain")
|
||||
and _sale(fixture, BACK_SALES, BACK, 300, "panel.back"), "front 20, hidden 300")
|
||||
var panel := OperatingLedgerPanel.new()
|
||||
root.add_child(panel)
|
||||
panel.setup(runtime, clock)
|
||||
panel.loan_amount.text = "200"
|
||||
panel.loan_amount.text_changed.emit("200")
|
||||
var hint: String = panel.get_node("LoanRepaymentHint").text
|
||||
_expect(not panel.repay_button.disabled and hint.contains("表金 20G・裏金 300G(計 320G)") and hint.contains("裏金から補填"), "a 200 repayment over front 20 is offered with the hidden fund")
|
||||
var key := StringName("ui.loan.repay.%d" % int(runtime.get_loan_principal_report()[&"next_command_id"]))
|
||||
panel.repay_button.pressed.emit()
|
||||
var entries: Array = economy.get_transaction_entries(economy.get_transaction_id_for_idempotency_key(key))
|
||||
_expect(entries.size() == 2 and entries[0].category == FinancePolicy.TOP_UP_CATEGORY and entries[0].amount == 180 and entries[1].category == &"LOAN_PRINCIPAL_REPAID" and entries[1].amount == 200,
|
||||
"one transaction: 180 hidden top-up, then the 200 principal")
|
||||
_expect(economy.get_balance(FRONT) == 0 and economy.get_balance(BACK) == 120 and -economy.get_balance(LOAN) == 800 and panel.get_node("LoanRepaymentResult").text.contains("200Gを返済"),
|
||||
"front 20 first, hidden 180 for the rest; 800 left")
|
||||
_expect(panel.repay_all_button.disabled and panel.get_node("LoanRepaymentHint").text.contains("完済には表金と裏金の合計が不足しています"), "full repayment of 800 waits: front + hidden is 120")
|
||||
panel.loan_amount.text = "500"
|
||||
panel.loan_amount.text_changed.emit("500")
|
||||
_expect(panel.repay_button.disabled, "500 over front + hidden 120 is not offered")
|
||||
var before: Dictionary = runtime.create_snapshot()
|
||||
panel.submit_repayment(true)
|
||||
panel.submit_repayment(false)
|
||||
_expect(var_to_bytes(before) == var_to_bytes(runtime.create_snapshot()), "pressed anyway, the unaffordable repayments change nothing")
|
||||
_expect(_sale(fixture, BACK_SALES, BACK, 700, "panel.back2"), "hidden funds reach 820")
|
||||
panel.refresh()
|
||||
_expect(not panel.repay_all_button.disabled, "full repayment of 800 is offered with front 0 and hidden 820")
|
||||
var full_key := StringName("ui.loan.repay.%d" % int(runtime.get_loan_principal_report()[&"next_command_id"]))
|
||||
panel.repay_all_button.pressed.emit()
|
||||
var full: Array = economy.get_transaction_entries(economy.get_transaction_id_for_idempotency_key(full_key))
|
||||
_expect(full.size() == 2 and full[0].category == FinancePolicy.TOP_UP_CATEGORY and full[0].amount == 800 and full[1].amount == 800,
|
||||
"the full repayment is one transaction, all from hidden funds")
|
||||
_expect(economy.get_balance(LOAN) == 0 and economy.get_balance(FRONT) == 0 and economy.get_balance(BACK) == 20 and fixture[&"state"].get_resource(&"gold") == 0, "the loan is repaid; front 0, hidden 20, Gold mirrors front funds")
|
||||
panel.queue_free()
|
||||
var saved: Dictionary = runtime.create_snapshot()
|
||||
_expect(runtime.restore_snapshot(saved) and var_to_bytes(saved) == var_to_bytes(runtime.create_snapshot()), "the panel repayments restore exactly")
|
||||
_free_fixture(fixture)
|
||||
|
||||
|
||||
# F7: the ordinary ledger panel reads both funds, the rank tax, the interest, the
|
||||
# top-ups and their arrears from the same ledger and daily closes.
|
||||
func _check_ledger_panel(runtime: Variant, clock: Variant) -> void:
|
||||
|
||||
Reference in New Issue
Block a user