initial commit
This commit is contained in:
171
Core/Service/Accounting/Money.lua
Normal file
171
Core/Service/Accounting/Money.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local Money = TSM.Accounting:NewPackage("Money")
|
||||
local Database = TSM.Include("Util.Database")
|
||||
local CSV = TSM.Include("Util.CSV")
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local private = {
|
||||
db = nil,
|
||||
dataChanged = false,
|
||||
}
|
||||
local CSV_KEYS = { "type", "amount", "otherPlayer", "player", "time" }
|
||||
local COMBINE_TIME_THRESHOLD = 300 -- group expenses within 5 minutes together
|
||||
local SECONDS_PER_DAY = 24 * 60 * 60
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function Money.OnInitialize()
|
||||
private.db = Database.NewSchema("ACCOUNTING_MONEY")
|
||||
:AddStringField("recordType")
|
||||
:AddStringField("type")
|
||||
:AddNumberField("amount")
|
||||
:AddStringField("otherPlayer")
|
||||
:AddStringField("player")
|
||||
:AddNumberField("time")
|
||||
:AddIndex("recordType")
|
||||
:Commit()
|
||||
private.db:BulkInsertStart()
|
||||
private.LoadData("expense", TSM.db.realm.internalData.csvExpense)
|
||||
private.LoadData("income", TSM.db.realm.internalData.csvIncome)
|
||||
private.db:BulkInsertEnd()
|
||||
end
|
||||
|
||||
function Money.OnDisable()
|
||||
if not private.dataChanged then
|
||||
-- nothing changed, so just keep the previous saved values
|
||||
return
|
||||
end
|
||||
TSM.db.realm.internalData.csvExpense = private.SaveData("expense")
|
||||
TSM.db.realm.internalData.csvIncome = private.SaveData("income")
|
||||
end
|
||||
|
||||
function Money.InsertMoneyTransferExpense(amount, destination)
|
||||
private.InsertRecord("expense", "Money Transfer", amount, destination, time())
|
||||
end
|
||||
|
||||
function Money.InsertPostageExpense(amount, destination)
|
||||
private.InsertRecord("expense", "Postage", amount, destination, time())
|
||||
end
|
||||
|
||||
function Money.InsertRepairBillExpense(amount)
|
||||
private.InsertRecord("expense", "Repair Bill", amount, "Merchant", time())
|
||||
end
|
||||
|
||||
function Money.InsertMoneyTransferIncome(amount, source, timestamp)
|
||||
private.InsertRecord("income", "Money Transfer", amount, source, timestamp)
|
||||
end
|
||||
|
||||
function Money.InsertGarrisonIncome(amount)
|
||||
private.InsertRecord("income", "Garrison", amount, "Mission", time())
|
||||
end
|
||||
|
||||
function Money.CreateQuery()
|
||||
return private.db:NewQuery()
|
||||
end
|
||||
|
||||
function Money.CharacterIterator(recordType)
|
||||
return private.db:NewQuery()
|
||||
:Equal("recordType", recordType)
|
||||
:Distinct("player")
|
||||
:Select("player")
|
||||
:IteratorAndRelease()
|
||||
end
|
||||
|
||||
function Money.RemoveOldData(days)
|
||||
private.dataChanged = true
|
||||
local query = private.db:NewQuery()
|
||||
:LessThan("time", time() - days * SECONDS_PER_DAY)
|
||||
local numRecords = 0
|
||||
private.db:SetQueryUpdatesPaused(true)
|
||||
for _, row in query:Iterator() do
|
||||
private.db:DeleteRow(row)
|
||||
numRecords = numRecords + 1
|
||||
end
|
||||
query:Release()
|
||||
private.db:SetQueryUpdatesPaused(false)
|
||||
return numRecords
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.LoadData(recordType, csvRecords)
|
||||
local decodeContext = CSV.DecodeStart(csvRecords, CSV_KEYS)
|
||||
if not decodeContext then
|
||||
Log.Err("Failed to decode %s records", recordType)
|
||||
private.dataChanged = true
|
||||
return
|
||||
end
|
||||
|
||||
for type, amount, otherPlayer, player, timestamp in CSV.DecodeIterator(decodeContext) do
|
||||
amount = tonumber(amount)
|
||||
timestamp = tonumber(timestamp)
|
||||
if amount and timestamp then
|
||||
local newTimestamp = floor(timestamp)
|
||||
if newTimestamp ~= timestamp then
|
||||
-- make sure all timestamps are stored as integers
|
||||
timestamp = newTimestamp
|
||||
private.dataChanged = true
|
||||
end
|
||||
private.db:BulkInsertNewRowFast6(recordType, type, amount, otherPlayer, player, timestamp)
|
||||
else
|
||||
private.dataChanged = true
|
||||
end
|
||||
end
|
||||
|
||||
if not CSV.DecodeEnd(decodeContext) then
|
||||
Log.Err("Failed to decode %s records", recordType)
|
||||
private.dataChanged = true
|
||||
end
|
||||
end
|
||||
|
||||
function private.SaveData(recordType)
|
||||
local query = private.db:NewQuery()
|
||||
:Equal("recordType", recordType)
|
||||
local encodeContext = CSV.EncodeStart(CSV_KEYS)
|
||||
for _, row in query:Iterator() do
|
||||
CSV.EncodeAddRowData(encodeContext, row)
|
||||
end
|
||||
query:Release()
|
||||
return CSV.EncodeEnd(encodeContext)
|
||||
end
|
||||
|
||||
function private.InsertRecord(recordType, type, amount, otherPlayer, timestamp)
|
||||
private.dataChanged = true
|
||||
assert(type and amount and amount > 0 and otherPlayer and timestamp)
|
||||
timestamp = floor(timestamp)
|
||||
local matchingRow = private.db:NewQuery()
|
||||
:Equal("recordType", recordType)
|
||||
:Equal("type", type)
|
||||
:Equal("otherPlayer", otherPlayer)
|
||||
:Equal("player", UnitName("player"))
|
||||
:GreaterThan("time", timestamp - COMBINE_TIME_THRESHOLD)
|
||||
:LessThan("time", timestamp + COMBINE_TIME_THRESHOLD)
|
||||
:GetFirstResultAndRelease()
|
||||
if matchingRow then
|
||||
matchingRow:SetField("amount", matchingRow:GetField("amount") + amount)
|
||||
matchingRow:Update()
|
||||
matchingRow:Release()
|
||||
else
|
||||
private.db:NewRow()
|
||||
:SetField("recordType", recordType)
|
||||
:SetField("type", type)
|
||||
:SetField("amount", amount)
|
||||
:SetField("otherPlayer", otherPlayer)
|
||||
:SetField("player", UnitName("player"))
|
||||
:SetField("time", timestamp)
|
||||
:Create()
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user