Skip to content

Commit

Permalink
Merge branch 'release/0.1.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
akhilgkrishnan committed Apr 25, 2022
2 parents 6bfacb2 + 278d8f4 commit aca380c
Show file tree
Hide file tree
Showing 121 changed files with 2,778 additions and 926 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ GOOGLE_OAUTH_CLIENT_SECRET='google-oauth-client-secret'

# Application Monitoring
NEW_RELIC_LICENSE_KEY='replace with newrelic licence key'

# Redis url
REDIS_URL='redis://127.0.0.1:6379/12'
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ group :development, :test do

# help to kill N+1 queries and unused eager loading. https://github.com/flyerhzm/bullet
gem "bullet"

# Background job processing adapter
gem "sidekiq"
end

group :development do
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,10 @@ GEM
activesupport (>= 3)
shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
sidekiq (6.4.1)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
simple_po_parser (1.1.5)
simplecov (0.21.2)
docile (~> 1.1)
Expand Down Expand Up @@ -516,6 +520,7 @@ DEPENDENCIES
selenium-webdriver (>= 4.0.0)
shoulda-callback-matchers (~> 1.1.1)
shoulda-matchers (~> 5.1)
sidekiq
simplecov
spring
stripe
Expand Down
2 changes: 2 additions & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-production}
worker: bundle exec sidekiq -e production -C config/sidekiq.yml
1 change: 1 addition & 0 deletions Procfile.dev
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
web: bin/rails s -b 0.0.0.0 -p 3000
webpacker: bin/webpack-dev-server
sidekiq: bundle exec sidekiq -e development -C config/sidekiq.yml
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,41 +37,45 @@ nvm install $(cat .nvmrc)
```
brew install postgresql
```
6. Install Redis
```
brew install redis
```

6. Install gem
7. Install gem

```
bundle install
```

7. Install node packages
8. Install node packages

```
yarn install
```

8. Setup ENV's
9. Setup ENV's

```
cp .env.example .env
```

9. Update `DATABASE_URL` in `.env` as per local `psql` creds. For example, if
10. Update `DATABASE_URL` in `.env` as per local `psql` creds. For example, if
the user is `root` and password is `password`, change the variable as
`DATABASE_URL="postgres://root:password@localhost/miru_web?encoding=utf8&pool=5&timeout=5000"`

10. Update `APP_BASE_URL` in `.env` to `localhost:3000`
11. Run `bin/rails db:create RAILS_ENV=development` to create the database
12. Run `bin/rails db:migrate RAILS_ENV=development` for migrations
13. Run `bin/rails db:seed` for populating the database with initial data
11. Update `APP_BASE_URL` in `.env` to `localhost:3000`
12. Run `bin/rails db:create RAILS_ENV=development` to create the database
13. Run `bin/rails db:migrate RAILS_ENV=development` for migrations
14. Run `bin/rails db:seed` for populating the database with initial data

14. Run app in local env
15. Run app in local env

```
foreman start -f Procfile.dev
```

15. Navigate to [http://0.0.0.0:3000](http://0.0.0.0:3000)
16. Navigate to [http://0.0.0.0:3000](http://0.0.0.0:3000)

### To receive the emails in non-production apps.

Expand Down
23 changes: 0 additions & 23 deletions app/controllers/clients_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,11 @@ def index
}
end

def create
client = Client.new(client_params)
authorize client
if client.save
redirect_to clients_path, notice: t("client.create.success")
else
flash.now[:error] = t("client.create.failure")
render :index, locals: {
clients:,
new_client: client,
keep_new_client_dialog_open: true
}, status: :unprocessable_entity
end
end

private

def clients
@_clients ||= current_company.clients.kept.order(created_at: :desc).map do |c|
c.attributes.merge({ hours_logged: c.timesheet_entries.sum(:duration) })
end
end

def client_params
params.require(:client).permit(
policy(Client).permitted_attributes
).tap do |client_params|
client_params[:company_id] = current_company.id
end
end
end
6 changes: 4 additions & 2 deletions app/controllers/concerns/error_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def user_not_authorized(exception)
error_key = policy.try(:error_message_key) || exception.query

message = I18n.t("#{policy_name}.#{error_key}", scope: "pundit", default: :default)

case policy.try(:error_message_key)
when :company_not_present
redirect_path = new_company_path
Expand Down Expand Up @@ -61,7 +60,10 @@ def record_not_discarded(exception)
def record_invalid(exception)
respond_to do |format|
format.json {
render json: { errors: exception.record.errors, notice: I18n.t("client.update.failure.message") },
render json: {
error: exception.record.errors.full_messages.first,
notice: I18n.t("client.update.failure.message")
},
status: :unprocessable_entity
}
format.html { render file: "public/422.html", status: :unprocessable_entity, layout: false, alert: message }
Expand Down
15 changes: 12 additions & 3 deletions app/controllers/internal_api/v1/clients_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,28 @@
class InternalApi::V1::ClientsController < InternalApi::V1::ApplicationController
def index
authorize Client
query = current_company.clients.ransack({ name_or_email_cont: params[:q] })
query = current_company.clients.kept.ransack({ name_or_email_cont: params[:q] })
clients = query.result(distinct: true)
client_details = clients.map { |client| client.client_detail(params[:time_frame]) }
total_minutes = (client_details.map { |client| client[:minutes_spent] }).sum
render json: { client_details:, total_minutes: }, status: :ok
overdue_outstanding_amount = current_company.overdue_and_outstanding_and_draft_amount
render json: { client_details:, total_minutes:, overdue_outstanding_amount: }, status: :ok
end

def create
authorize Client
render :create, locals: {
client: Client.create!(client_params)
}
end

def show
authorize client
project_details = client.project_details(params[:time_frame])
client_details = { id: client.id, name: client.name, email: client.email }
total_minutes = (project_details.map { |project| project[:minutes_spent] }).sum
render json: { client_details:, project_details:, total_minutes: }, status: :ok
overdue_outstanding_amount = client.client_overdue_and_outstanding_calculation
render json: { client_details:, project_details:, total_minutes:, overdue_outstanding_amount: }, status: :ok
end

def update
Expand Down
22 changes: 14 additions & 8 deletions app/controllers/internal_api/v1/invoices_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

class InternalApi::V1::InvoicesController < InternalApi::V1::ApplicationController
before_action :load_client, only: [:create, :update]
after_action :ensure_time_entries_billed, only: [:send_invoice]

def index
authorize Invoice
Expand All @@ -10,17 +11,14 @@ def index
.from_date(params[:from])
.to_date(params[:to])
.for_clients(params[:client_ids])
.with_statuses(params[:statuses]),
.with_statuses(params[:statuses])
.order(created_at: :desc),
items_param: :invoices_per_page)

render :index, locals: {
invoices:,
pagy: pagy_metadata(pagy),
summary: {
overdue_amount: current_company.invoices.overdue.sum(:amount),
outstanding_amount: current_company.invoices.sum(:outstanding_amount),
draft_amount: current_company.invoices.draft.sum(:amount)
}
summary: current_company.overdue_and_outstanding_and_draft_amount
}
end

Expand All @@ -45,7 +43,11 @@ def update
def send_invoice
authorize invoice

invoice.send_to_email(subject: invoice_email_params[:subject], recipients: invoice_email_params[:recipients])
invoice.send_to_email(
subject: invoice_email_params[:subject],
message: invoice_email_params[:message],
recipients: invoice_email_params[:recipients]
)

render json: { message: "Invoice will be sent!" }, status: :accepted
end
Expand All @@ -68,6 +70,10 @@ def invoice_params
end

def invoice_email_params
params.require(:invoice_email).permit(:subject, :body, recipients: [])
params.require(:invoice_email).permit(:subject, :message, recipients: [])
end

def ensure_time_entries_billed
invoice.update_timesheet_entry_status!
end
end
25 changes: 25 additions & 0 deletions app/controllers/invoices_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
# frozen_string_literal: true

class InvoicesController < ApplicationController
before_action :load_invoice, only: [:show]

def index
authorize :invoice
end

def show
authorize Invoice
render :show, locals: {
invoice: @invoice
}
end

private

def load_invoice
@invoice = Invoice.includes(:invoice_line_items, :client)
.find(params[:id]).as_json(include: [:invoice_line_items, :client])
.merge(company: {
id: current_company.id,
logo: current_company.logo.attached? ? polymorphic_url(current_company.logo) : "",
name: current_company.name,
phone_number: current_company.business_phone,
address: current_company.address,
country: current_company.country,
currency: current_company.base_currency
})
end
end
7 changes: 7 additions & 0 deletions app/controllers/payments_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class PaymentsController < ApplicationController
def index
authorize :index, policy_class: PaymentPolicy
end
end
18 changes: 0 additions & 18 deletions app/controllers/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,4 @@ class ProjectsController < ApplicationController
def index
authorize Project
end

def create
project = Project.new(project_params)

if project.save
flash[:notice] = t(".success")
else
flash[:alert] = t(".failure")
end

redirect_to projects_path
end

private

def project_params
params.require(:project).permit(:client_id, :name, :billable)
end
end
13 changes: 8 additions & 5 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ class Users::SessionsController < Devise::SessionsController
def after_sign_in_path_for(resource)
return new_company_path if resource.companies.empty? && resource.has_role?(:owner)

if resource.has_owner_or_admin_role?(current_company)
dashboard_index_path
else
time_tracking_index_path
end
time_tracking_index_path

# As per discussion we want to redirect all the users to time-tracking page as dashboard is blank.
# if resource.has_owner_or_admin_role?(current_company)
# dashboard_index_path
# else
# time_tracking_index_path
# end
end
end
Empty file removed app/javascript/src/apis/client.ts
Empty file.
6 changes: 5 additions & 1 deletion app/javascript/src/apis/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ const path = "/clients";

const get = async (queryParam) => axios.get(`${path}${queryParam}`);

const create = async (payload) => axios.post(`${path}`, payload);

const show = async (id, queryParam) => axios.get(`${path}/${id}${queryParam}`);

const update = async (id, payload) => axios.patch(`${path}/${id}`, payload);

const destroy = async id => axios.delete(`${path}/${id}`);

const clients = { update, destroy, get };
const clients = { update, destroy, get, show, create };

export default clients;
12 changes: 10 additions & 2 deletions app/javascript/src/apis/invoices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ import axios from "axios";

const path = "/invoices";

const get = async () => axios.get(`${path}`);
const get = async (query = "") =>
axios.get(query ? `${path}?${query}` : `${path}`);

const invoicesApi = { get };
const post = async (body) => axios.post(`${path}`, body);

const patch = async (id, body) => axios.post(`${path}/${id}`, body);

const sendInvoice = async (id, payload) =>
axios.post(`${path}/${id}/send_invoice`, payload);

const invoicesApi = { get, post, patch, sendInvoice };

export default invoicesApi;
Loading

0 comments on commit aca380c

Please sign in to comment.