Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions accounting/app/consumers/task_changes_consumer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

# Example consumer that prints messages payloads
class TaskChangesConsumer < ApplicationConsumer
def consume
messages.each do |m|
message = m.payload
puts '-' * 80
p message
puts '-' * 80

process_message(message)
end
end

private

def process_message(message)
case message['event_name']
when 'Task.Created' # CUD
# ignore
when 'Task.Updated' # CUD
task = Task.find_by(public_id: message['data']['public_id'])
return unless task

task.update!(title: message['data']['title'])
when 'Task.Added' # BE
Task.transaction do
task = Task.create!(
public_id: message['data']['public_id'],
title: message['data']['title']
)
user = User.find_or_create_by!(public_id: message['data']['assigned_to']['public_id'])
account = user.accounts.take || user.accounts.create!(
public_id: SecureRandom.uuid,
label: 'Default user account',
currency: Account::DEFAULT_CURRENCY
)
account.statements.create!(
credit: task.assign_price,
description: "#{task.title} assigned",
ref: task
)
account.update_balance!
task
end
when 'Task.Assigned'
task = Task.find_by!(public_id: message['data']['public_id'])
user = User.find_by!(public_id: message['data']['assigned_to']['public_id'])
account = user.accounts.take!
account.statements.create!(
credit: task.assign_price,
description: "Task #{task.title} reassigned",
ref: task
)
account.update_balance!
task
when 'Task.Resolved' # BE
task = Task.find_by!(public_id: message['data']['public_id'])
user = User.find_by!(public_id: message['data']['assigned_to']['public_id'])
account = user.accounts.take
account.statements.create!(
debit: task.resolve_price,
description: "Task #{task.title} resolved",
ref: task
)
account.update_balance!
task
end
rescue => e
puts "Processing failed: #{e}"
puts message
end
end
73 changes: 73 additions & 0 deletions accounting/app/consumers/user_changes_consumer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frozen_string_literal: true

# Example consumer that prints messages payloads
class UserChangesConsumer < ApplicationConsumer
def consume
messages.each do |m|
message = m.payload
puts '-' * 80
p message
puts '-' * 80

case message['event_name']
when 'Account.Created'
user = fetch_user(message['data']['public_id'])
if user
user.update(
public_id: message['data']['public_id'],
email: message['data']['email'],
full_name: message['data']['full_name'],
role: message['data']['position']
)
else
create_user(message['data'])
end
when 'Account.Updated'
fetch_user(message['data']['public_id'])&.update!(
full_name: message['data']['full_name']
)
when 'Account.Deleted'
fetch_user(message['data']['public_id'])&.destroy!
# TODO: if you want
when 'Account.RoleChanged'
fetch_user(message['data']['public_id'])&.update!(
role: message['data']['role']
)
else
# store events in DB
end
end
end

# Run anything upon partition being revoked
# def revoked
# end

# Define here any teardown things you want when Karafka server stops
# def shutdown
# end


private

def fetch_user(p_id)
User.find_by(public_id:p_id)
end

def create_user(data)
User.transaction do
user = User.create!(
public_id: data['public_id'],
email: data['email'],
full_name: data['full_name'],
role: data['position']
)
user.accounts.create!(
public_id: SecureRandom.uuid,
label: 'Default user account',
currency: Account::DEFAULT_CURRENCY
)
user
end
end
end
12 changes: 12 additions & 0 deletions accounting/app/controllers/accounts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class AccountsController < ApplicationController
before_action :require_user_logged_in!

def index
@accounts = current_user.accounts.order(:id)
end

def show
@account = current_user.accounts.find(params[:id])
@statements = @account.statements.preload(:ref).order(id: :desc)
end
end
8 changes: 8 additions & 0 deletions accounting/app/helpers/accounts_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module AccountsHelper
def today_profit
@today_profit ||= begin
row = Statement.today.task_related.totals.take
(row&.total_credit || 0).abs + (row&.total_debit || 0)
end
end
end
3 changes: 3 additions & 0 deletions accounting/app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
module ApplicationHelper
def current_user
request.env['warden'].user
end
end
12 changes: 12 additions & 0 deletions accounting/app/models/account.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Account < ApplicationRecord
DEFAULT_CURRENCY = 'INR'
belongs_to :user
has_many :statements

def update_balance!
balance_row = statements.totals.take!
update!(
cached_balance: (balance_row.total_credit || 0) + (balance_row.total_debit || 0)
)
end
end
3 changes: 3 additions & 0 deletions accounting/app/models/auth_provider.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class AuthProvider < ApplicationRecord
belongs_to :user
end
38 changes: 38 additions & 0 deletions accounting/app/models/statement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class Statement < ApplicationRecord
belongs_to :account
belongs_to :ref, polymorphic: true

scope :totals, -> { select('SUM(credit) as total_credit, SUM(debit) as total_debit') }
scope :today, -> { where('DATE(created_at) = CURRENT_DATE') }
scope :for_date, ->(date) { where("DATE(created_at) = ?", date) }
scope :task_related, -> { where(ref_type: 'Task') }

after_create do
statement = self
event_name = 'Statement.Created'
event = {
event_id: SecureRandom.uuid,
event_version: 1,
event_time: Time.now.to_s,
producer: 'accounting_service',
event_name: event_name,
data: {
owner: {public_id: statement.account.user.public_id},
description: statement.description,
credit: statement.credit || 0,
debit: statement.debit || 0,
ref_type: statement.ref_type,
ref_public_id: statement.ref.public_id
}
}

result = SchemaRegistry.validate_event(event, event_name.underscore, version: event[:event_version])

if result.success?
KAFKA_PRODUCER.produce_sync(topic: 'statements-stream', payload: event.to_json)
else
puts "Event validation error: #{result.failure}"
puts "Event data: #{event.inspect}"
end
end
end
8 changes: 8 additions & 0 deletions accounting/app/models/task.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Task < ApplicationRecord
def initialize(*, **)
super

self.assign_price ||= rand(10) - 20
self.resolve_price ||= rand(20) + 20
end
end
24 changes: 24 additions & 0 deletions accounting/app/models/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class User < ApplicationRecord
has_many :auth_providers
has_many :accounts

def self.close_day(date = Date.yesterday)
User.find_each do |user|
user.accounts.each do |account|
next if account.statements.for_date(date).where(ref: user, description: "Payout for #{date}").exists?

day_result = account.statements.task_related.for_date(date).totals.take
day_balance = (day_result.total_credit || 0) + (day_result.total_debit || 0)
if day_balance.positive?
account.statements.create!(
credit: -day_balance,
description: "Payout for #{date}",
ref: user,
created_at: date.end_of_day
)
# Send mail
end
end
end
end
end
5 changes: 5 additions & 0 deletions accounting/app/views/accounts/_account.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<tr id="<%= dom_id account %>">
<td><%= account.public_id %></td>
<td><%= link_to account.label, account %></td>
<td><%= account.cached_balance %></td>
</div>
23 changes: 23 additions & 0 deletions accounting/app/views/accounts/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<h1>Today profit: <%= today_profit %></h1>
<h3>User accounts (<%= current_user.full_name %>, <%= current_user.public_id %>)</h3>

<div id="accounts">
<table>
<thead>
<th>Public ID</th>
<th>Name</th>
<th>Balance</th>
</thead>
<% @accounts.each do |account| %>
<%= render account %>
<tr>

</tr>

<p>

</p>
<% end %>
</table>

</div>
28 changes: 28 additions & 0 deletions accounting/app/views/accounts/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<h1>
Account # <%= @account.label %>
</h1>

<div id="statements">
<table>
<thead>
<tr>
<th>Ref</th>
<th>Desc</th>
<th>Credit</th>
<th>Debit</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<% @statements.each do |statement| %>
<tr>
<td><%= statement.ref.class %> #<%= statement.ref.public_id %></td>
<td><%= statement.description %></td>
<td><%= statement.credit %></td>
<td><%= statement.debit %></td>
<td><%= statement.created_at %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
7 changes: 7 additions & 0 deletions accounting/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@

# Defines the root path route ("/")
# root "articles#index"

get '/logout', to: 'oauth_session#destroy'
get '/auth/:provider/callback', to: 'oauth_session#create'

resources :accounts, only: %i[index show] do
resources :statements, only: %i[index]
end
end
24 changes: 24 additions & 0 deletions accounting/config/schedule.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Use this file to easily define all of your cron jobs.
#
# It's helpful, but not entirely necessary to understand cron before proceeding.
# http://en.wikipedia.org/wiki/Cron

# Example:
#
# set :output, "/path/to/my/cron_log.log"
#
# every 2.hours do
# command "/usr/bin/some_great_command"
# runner "MyModel.some_method"
# rake "some:great:rake:task"
# end
#
# every 4.days do
# runner "AnotherModel.prune_old_records"
# end

# Learn more: http://github.com/javan/whenever

every 1.day, at: '1:00 am' do
runner "User.close_day"
end
12 changes: 12 additions & 0 deletions accounting/db/migrate/20221008144037_create_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :public_id
t.string :full_name
t.string :email
t.string :role

t.timestamps
end
end
end
13 changes: 13 additions & 0 deletions accounting/db/migrate/20221008144527_create_auth_providers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateAuthProviders < ActiveRecord::Migration[7.0]
def change
create_table :auth_providers do |t|
t.integer :user_id
t.string :uid
t.string :provider
t.string :username
t.jsonb :user_info

t.timestamps
end
end
end
Loading