如何设计一个可以跟踪两个用户之间的余额的数据库,以及保留所有交易的日志,而不会重复数据?
奖励: Ruby on Rails引用将非常棒
我正在尝试制作一个可以跟踪人们的IOU的webapp,但是我很难绕过如何建模数据库。这些都是硬性要求
User
个对象具有以下方法:
User#account_info
:用户帐户的摘要
amount_payable
:用户欠款amount_receivable
:欠用户的金额User#payables
:用户所欠人数和金额的列表
user
:欠下的另一个amount
:欠款User#receivables
用户ID所欠人数和金额的列表
user
:欠我们的另一个amount
:欠款User#transactions
过去交易清单:
type
:give
或take
user
:此次交易中的另一个amount
:欠款User#give
:给别人钱
user
:此次交易中的另一个amount
:欠款nil
User#take
:从别人那里拿钱
user
:此次交易中的另一个amount
:欠款nil
以下是用户之间的互动如何发挥
### Initialize new users
a = User.new
b = User.new
c = User.new
## Users owe and are owed nothing
a.account_info
# {amount_payable: 0, amount_receivable: 0}
b.account_info
# {amount_payable: 0, amount_receivable: 0}
## Users have no payables or receivables
a.receivables
# []
b.receivables
# []
## Users have no transactions
a.transactions
# []
b.transactions
# []
a.takes(from: b, amount: 10)
# nil
## A now owes $10
a.account_info
# {amount_payable: 10, amount_receivable: 0}
# B is now owed $10
# {amount_payable: 0, amount_receivable: 10}
a.payables
# [{user: b.id, amount: 5}}]
b.receivables
# [{user: a.id, amount: 5}}]
## A has transactions
a.transactions
# [{type: 'take', user: b.id, amount: 10}]
## B has transactions
b.transactions
# [{type: 'give', user: a.id, amount: 10}]
a.gives(to: b, amount: 10)
#nil
# a now owes $5
a.account_info
# {amount_payable: 10, amount_receivable: 0}
# b is now owed $5
# {amount_payable: 0, amount_receivable: 10}
a.transactions
# [{type: 'give', user: b.id, amount: 5}, {type: 'take', user: b.id, amount: 10}]
## B has transactions
b.transactions
# [{type: 'take', user: a.id, amount: 5}, {type: 'give', user: a.id, amount: 10}]
a.payables
# [{user: b.id, amount: 5}}]
b.receivables
# [{user: a.id, amount: 5}}]
(这花了我三天时间和无数头痛)
这个解决方案非常hacky
def User << ActiveRecord::Base
has_one :wallet
end
def Wallet << ActiveRecord::Base
belongs_to :user
has_many :accounts
end
def Account << ActiveRecord::Base
has_many :transfers
# balance - integer
# creditor - user_id, class: Wallet
# debtor - user_id. class: Wallet
end
def Transfer << ActiveRecord::Base
belongs_to :account
# amount - integer
# datetime - datetime
end
鉴于以上模型:
神奇发生在Accounts
模型中:
交易是转移的运行日志:
这样,我们在以下情况下确定用户欠款:
答案 0 :(得分:2)
老实说,现在不想写出所有这些问题,所以我只想指出你想要的方向。
首先,你的表格过于复杂
# Tables:
def User << ActiveRecord::Base
has_one :wallet
has_many :transactions
# General user info
# wallet_id
end
def Transfers << ActiveRecord::Base
belongs_to :creditor (user)
belongs_to :debtor (user)
# amount - integer
# timestamps
# creditor_id
# debtor_id
end
这就是你所需要的一切。
您需要使用ActiveRecord::Base.transactions do
来更新帐户。
在您的用户类中构建.gives函数。
User.gives(to: b, amount: 10)
# Create transfer
# Transfer.create({ amount:10, creditor: a.id, debtor: b.id })
在您的用户类中构建.takes函数。
User.takes(from: b, amount: 10)
# Create transfer
# Transfer.create({ amount:10, creditor: b.id, debtor: a.id })
转移是一个简单的有很多关系
User.Transfers
has_many :Transfers
应付账款,应收账款,Account_info是一个更深入的SQL查询,但没有什么太疯狂。它会看起来像这样(不完全),如果你不能从下面这个评论中得到它。今晚我可以回来尝试解决这些问题。
a.payables
# SQL query
# SELECT SUM(amount_payable.amount) - SUM (amount_receivable.amount)
# FROM User
# WHERE User = a
# JOIN Transfer AS amount_payable ON Creditor == a
# JOIN Transfer AS amount_receivable ON Creditor == amount_payable.debitor
# GROUPBY amount_payable.debitor
# HAVING SUM(amount_payable.amount) - SUM (amount_receivable.amount) > 0
User.receivables会反转债权人和债务人的位置。
Account_Info会在连接表上加倍,并具有更多特定的AS语句
答案 1 :(得分:0)
我对RoR一无所知,所以我不能用这种方式说出来。但这是一个相当简单的数据库问题。您只需要三个表:用户,贷款和付款。每笔贷款都有贷款人和贷款人。每笔贷款都有付款。
用户表只需要一个唯一的ID和有关用户的信息。
贷款表将有两个用户表的外键,一个用于贷方,一个用于收件人。这将包括贷款金额。它会在借钱时创造出来。对于单个贷方或收件人用户,此表可以有任意数量的条目。
付款表只是一笔贷款付款清单。它有一个到贷款表的外键链接。这是一对多关系的多方面。
因此,要了解用户借出的贷款,请对用户和贷款进行查询,并将其与贷款中的贷方外键相关联。同样,对于已收到贷款的用户,您使用收件人外键。
我不会将贷款余额存入贷款表,因为那时你有两个事实来源 - 支付表和贷款表。最好只在需要时计算剩余的贷款余额。关系数据库非常擅长在非常大的数据集上执行此操作。
答案 2 :(得分:0)
你做这件事的方式很好,但我会做一些调整。除非有某些特定原因,否则您不一定需要钱包课程。您可以在用户类本身中跟踪它们的平衡。
内部账户,我没有债权人和债务人ID,我只有2个user_id,保持余额为正,并跟踪谁是欠债的人。这样你就不需要摆弄负片,并简化了大量的簿记工作。