# frozen_string_literal: true
describe ESM::Command::Territory::Pay, category: "command" do
include_context "command"
include_examples "validate_command"
describe "V1" do
describe "#execute" do
include_context "connection_v1"
context "when the execution is valid" do
it "returns a success message" do
request = execute!(
channel_type: :dm,
arguments: {server_id: server.server_id, territory_id: Faker::Crypto.md5[0, 5]}
)
expect(request).not_to be_nil
wait_for { connection.requests }.to be_blank
ESM.discord_bot.test_outbox.await_size(1)
embed = ESM.discord_bot.test_outbox.first.content
expect(embed.description).to match(/has successfully received the payment/i)
end
end
end
end
describe "V2", v2: true do
it "is a player command" do
expect(command.type).to eq(:player)
end
describe "#on_execute", requires_connection: true do
include_context "connection" do
let!(:territory_build_rights) { [user.steam_uid] }
end
let(:locker_balance) { 1_000_000 } # Aww yea
let!(:territory_price_per_object) do
execute_sqf!(
<<~STRING
getNumber (missionConfigFile >> "CfgTerritories" >> "popTabAmountPerObject")
STRING
)
end
let(:territory_protection_price) do
territory.level * territory_price_per_object * territory.number_of_constructions
end
subject(:execute_command) do
execute!(arguments: {territory_id: territory.encoded_id, server_id: server.server_id})
end
before do
user.exile_account.update!(locker: locker_balance)
territory.number_of_constructions = 15
territory.create_flag
end
# Happy path
shared_examples "successful_territory_payment" do
it "pays the territory's protection money using poptabs from the player's locker" do
execute_command
# Player response, admin log, xm8 notification
ESM.discord_bot.test_outbox.await_size(2)
# Player response
expect(
ESM.discord_bot.test_outbox.retrieve(
"Successfully paid protection money for territory `#{territory.encoded_id}`"
)
).not_to be(nil)
# Admin log
expect(
ESM.discord_bot.test_outbox.retrieve("Territory protection money paid")
).not_to be(nil)
user.exile_account.reload
# Handle taxes
tax = respond_to?(:territory_payment_tax) ? territory_payment_tax : 0
tax = (territory_protection_price * (tax / 100.0)).round if tax > 0
expect(user.exile_account.locker).to eq(locker_balance - territory_protection_price - tax)
territory.reload
# Check for increased payment counter
expect(territory.esm_payment_counter).to eq(1)
# Check for time change
expect(territory.last_paid_at).not_to be(nil)
end
end
context "when the territory protection money is paid" do
it "sends an XM8 notification" do
execute_command
notifications = ESM::ExileXm8Notification.protection_money_paid.sent
wait_for { notifications.size }.to eq(1)
end
end
context "when the player is online, is a builder, and pays the territory" do
before { spawn_player_for(user) }
include_examples "successful_territory_payment"
end
context "when the player is offline, is a builder, and pays the territory" do
include_examples "successful_territory_payment"
end
context "when the player is a territory admin" do
let!(:territory_admin_uids) { [user.steam_uid] }
before do
territory.revoke_membership(user.steam_uid)
expect(territory.build_rights).not_to include(user.steam_uid)
end
include_examples "successful_territory_payment"
end
context "when there is tax on the payment" do
let(:territory_payment_tax) { Faker::Number.between(from: 1, to: 100) }
before do
server.server_setting.update!(territory_payment_tax:)
end
include_examples "successful_territory_payment" do
it { expect(territory_payment_tax).not_to eq(0) }
end
end
# max_payment_count caps remote (ESM) payments per territory. The counter
# climbs on each payment and is reset when the player logs into the server.
describe "the remote payment limit" do
context "when the limit is enabled and the territory is under it" do
before do
server.server_setting.update!(max_payment_count: 5)
reinitialize_server! # post-init re-sends the new cap to the extension
end
# Counter starts at 0 (< 5), so this pays and bumps it to 1.
include_examples "successful_territory_payment"
end
context "when the territory has reached the limit" do
let(:max_payment_count) { 3 }
before do
server.server_setting.update!(max_payment_count:)
territory.update!(esm_payment_counter: max_payment_count)
reinitialize_server! # post-init re-sends the new cap to the extension
end
it "rejects the payment and leaves the locker and counter untouched" do
expect { execute_command }.to raise_error(ESM::Exception::ExtensionError) do |error|
expect(error.to_embed.description).to match(/hit the remote payment limit/)
end
user.exile_account.reload
expect(user.exile_account.locker).to eq(locker_balance)
territory.reload
expect(territory.esm_payment_counter).to eq(max_payment_count)
end
end
context "when the limit is disabled (max_payment_count is 0)" do
before do
server.server_setting.update!(max_payment_count: 0)
territory.update!(esm_payment_counter: 10) # well past any cap
reinitialize_server! # post-init re-sends the new cap to the extension
end
it "pays regardless of the counter" do
execute_command
ESM.discord_bot.test_outbox.await_size(2)
expect(
ESM.discord_bot.test_outbox.retrieve(
"Successfully paid protection money for territory `#{territory.encoded_id}`"
)
).not_to be(nil)
user.exile_account.reload
expect(user.exile_account.locker).to eq(locker_balance - territory_protection_price)
end
end
end
context "when the player has not joined the server" do
before { user.exile_account.destroy! }
include_examples "arma_error_player_needs_to_join"
end
context "when the territory is null" do
before { territory.delete_flag }
include_examples "arma_error_null_flag"
end
context "when the player is not a member of this territory" do
before { territory.revoke_membership(user.steam_uid) }
include_examples "arma_error_missing_territory_access"
end
context "when the flag has been stolen" do
before { territory.update!(flag_stolen: true) }
include_examples "arma_error_flag_stolen"
end
context "when the player is online and does not have enough poptabs" do
let!(:locker_balance) { 0 }
before { spawn_player_for(user) }
include_examples "arma_error_too_poor_with_cost"
end
context "when the player is not online and does not have enough poptabs" do
let!(:locker_balance) { 0 }
include_examples "arma_error_too_poor_with_cost"
end
end
end
end