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
40 changes: 40 additions & 0 deletions app/controllers/admin/invoices/mark_as_paids_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Admin
module Invoices
class MarkAsPaidsController < BaseController
rescue_from Errors::InvoiceAlreadyPaid, with: :invoice_already_paid

before_action :set_invoice

# order is important! before set invoice, otherwise @invoice wont be set
include ::Invoices::UpdateAuthorizable

def edit; end

def update
raise(Errors::InvoiceAlreadyPaid, @invoice.id) if @invoice.paid?

@invoice.assign_attributes(invoice_params)
@invoice.mark_as_paid_at(invoice_params[:paid_at])
@invoice.save!

flash[:notice] = t('invoices.marked_as_paid')
redirect_to admin_invoice_path(@invoice), status: :see_other
end

private

def set_invoice
@invoice = Invoice.find(params[:invoice_id])
end

def invoice_already_paid
flash[:alert] = t('invoices.already_paid')
redirect_to admin_invoice_path(@invoice), status: :see_other
end

def invoice_params
params.require(:invoice).permit(:notes, :paid_at)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Admin
module Invoices
class TogglePartialPaymentsController < BaseController
before_action :set_invoice

# order is important! before set invoice, otherwise @invoice wont be set
include ::Invoices::UpdateAuthorizable

def update
if @invoice.toggle(:partial_payments).save

action = @invoice.partial_payments? ? 'activated' : 'deactivated'
redirect_to admin_invoice_path(@invoice), notice: t("invoices.partial_payments_#{action}"), status: :see_other
else
redirect_to admin_invoice_path(@invoice), alert: t(:something_went_wrong), status: :see_other
end
end

def set_invoice
@invoice = Invoice.find(params[:invoice_id])
end
end
end
end
70 changes: 2 additions & 68 deletions app/controllers/admin/invoices_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
module Admin
class InvoicesController < BaseController
before_action :authorize_user
before_action :create_invoice_if_needed, except: :toggle_partial_payments
before_action :set_invoice, only: %i[show download update edit toggle_partial_payments]
before_action :authorize_for_update, only: %i[edit update]
before_action :create_invoice_if_needed
before_action :set_invoice, only: %i[show download]

# GET /admin/invoices/aa450f1a-45e2-4f22-b2c3-f5f46b5f906b
def show
Expand All @@ -24,7 +23,6 @@ def index
else
@pagy, @invoices = pagy(invoices, items: params[:per_page] ||= 15)
end

end

# GET /admin/invoices/aa450f1a-45e2-4f22-b2c3-f5f46b5f906b/download
Expand All @@ -35,80 +33,16 @@ def download
send_data(raw_pdf, filename: @invoice.filename)
end

# GET /admin/invoices/aa450f1a-45e2-4f22-b2c3-f5f46b5f906b/edit
def edit
if @invoice.paid?
respond_to do |format|
format.html do
redirect_to admin_invoice_path(@invoice), notice: t('invoices.already_paid')
end
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end
end

# PUT /admin/invoices/aa450f1a-45e2-4f22-b2c3-f5f46b5f906b
def update
respond_to do |format|
if update_predicate
format.html do
redirect_to admin_invoice_path(@invoice), notice: t('invoices.marked_as_paid')
end
format.json { render :show, status: :ok, location: @invoice }
else
format.html { redirect_to admin_invoice_path(@invoice), notice: t(:something_went_wrong) }
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end
rescue Errors::InvoiceAlreadyPaid
respond_to do |format|
format.html { redirect_to admin_invoice_path(@invoice), notice: t('invoices.already_paid') }
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end

# POST /admin/invoices/aa450f1a-45e2-4f22-b2c3-f5f46b5f906b/toggle_partial_payments
def toggle_partial_payments
respond_to do |format|
if @invoice.toggle(:partial_payments).save
format.html do
action = @invoice.partial_payments? ? 'activated' : 'deactivated'
redirect_to admin_invoice_path(@invoice), notice: t("invoices.partial_payments_#{action}")
end
format.json { render :show, status: :ok, location: @invoice }
else
format.html { redirect_to admin_invoice_path(@invoice), notice: t(:something_went_wrong) }
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end
end

private

def set_invoice
@invoice = Invoice.includes(:invoice_items).find(params[:id])
end

def update_params
update_params = params.require(:invoice).permit(:notes)
merge_updated_by(update_params)
end

def update_predicate
@invoice.assign_attributes(update_params)
raise(Errors::InvoiceAlreadyPaid, @invoice.id) if @invoice.paid?

@invoice.mark_as_paid_at(Time.zone.now)
end

def authorize_user
authorize! :read, Invoice
end

def authorize_for_update
authorize! :update, @invoice
end

def create_invoice_if_needed
InvoiceCreationJob.perform_later if InvoiceCreationJob.needs_to_run?
end
Expand Down
20 changes: 20 additions & 0 deletions app/controllers/concerns/invoices/update_authorizable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Invoices
module UpdateAuthorizable
extend ActiveSupport::Concern

included do
before_action :authorize_user
before_action :authorize_for_update
end

private

def authorize_user
authorize! :read, Invoice
end

def authorize_for_update
authorize! :update, @invoice
end
end
end
40 changes: 40 additions & 0 deletions app/views/admin/invoices/mark_as_paids/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

<%= turbo_frame_tag "modal" do %>

<div data-controller='modals--offer-modal' data-modals--offer-modal-open-class='is-open'>
<div class="c-modal-overlay js-modal-po" data-modals--offer-modal-target='modal'>
<div class="c-modal">
<div class="c-modal__scroll">
<div class="c-modal__scroll__content">
<button class="c-modal__close-btn js-close-modal" data-action='modals--offer-modal#close'>
<span class="o-close-icon"></span>
</button>
<div class="c-modal__header">
<div class="c-modal__header__title">
<span class="o-edit-icon--green"></span>
<span><%= t('invoices.mark_as_paid') %></span>
</div>
<div class="c-modal__header__subject">
<span class="c-modal__header__subject__title"><%= @invoice.number %></span>
<span class="o-io-icon o-io-icon--bg-blue"></span>
</div>
</div>

<div>
<%= form_with model: @invoice, url: admin_invoice_mark_as_paid_path(@invoice), method: :patch, data: { turbo: false } do |f| %>
<div class="c-modal__grid u-flex-wrap u-mt-24 u-mt-48-l">
<%= f.text_area :notes %>
<%= f.date_field :paid_at %>
<%= f.submit t('invoices.mark_as_paid') %>
</div>
<% end %>
</div>

</div>
</div>
</div>
</div>
</div>


<% end %>
108 changes: 66 additions & 42 deletions app/views/admin/invoices/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,56 +1,77 @@
<% content_for :title, t('.title', invoice_number: @invoice&.number) %>

<div class="o-container">
<div class="c-table__filters" >
<%= link_to t(:versions_name), admin_invoice_versions_path(@invoice), class: "ui button primary" %>
<%= link_to t('invoices.download'), download_admin_invoice_path(@invoice),
{ class: 'ui button secondary', download: true } %>
<% unless @invoice.overdue? || @invoice.paid? %>
<%= link_to t('invoices.mark_as_paid'), edit_admin_invoice_path(@invoice), class: "ui button secondary" %>
<% action = @invoice.partial_payments? ? "disallow" : "allow" %>
<%= button_to t("invoices.#{action}_partial_payments"), toggle_partial_payments_admin_invoice_path(@invoice), class: "ui button secondary", form: { data: { 'turbo-confirm': 'Are you sure?' } } %>
<% end %>
<div class="c-block">
<div style="display: flex; gap: 1rem; align-items: center; margin-bottom: 1.5rem; flex-wrap: wrap;">
<%= link_to t(:versions_name), admin_invoice_versions_path(@invoice), class: "c-btn c-btn--ghost c-acount__button c-acount__button--icon" %>
<%= link_to t('invoices.download'), download_admin_invoice_path(@invoice), { class: 'c-btn c-btn--ghost c-acount__button c-acount__button--icon', download: true } %>

<% unless @invoice.overdue? || @invoice.paid? %>
<%= link_to t('invoices.mark_as_paid'), edit_admin_invoice_mark_as_paid_path(@invoice), class: "c-btn c-btn--ghost c-acount__button c-acount__button--icon", data: { turbo_frame: 'modal' } %>

<% action = @invoice.partial_payments? ? "disallow" : "allow" %>
<%= button_to t("invoices.#{action}_partial_payments"), admin_invoice_toggle_partial_payment_path(@invoice), class: "c-btn c-btn--ghost c-acount__button c-acount__button--icon", form: { data: { 'turbo-confirm': 'Are you sure?' } }, method: :patch %>
<% end %>
</div>
</div>

<div class="c-block">
<div class="o-grid o-grid--two-col">
<div>
<div class="header"><%= t('invoices.status') %></div>
<%= I18n.t("activerecord.enums.invoice.statuses.#{@invoice.status}") %>
<div class="header"><%= t('invoices.issued_for') %></div>
<%= @invoice.recipient %><br>
<%= @invoice.address %>
<div class="header"><%= t(:updated_by) %></div>
<%= @invoice.updated_by %>
<h2 class="c-block__title u-h3"><%= t('invoices.info_block') %></h2>
<table class="table--black" style="width:100%">
<tbody>
<tr>
<td><%= t('invoices.status') %></td>
<td><%= I18n.t("activerecord.enums.invoice.statuses.#{@invoice.status}") %></td>
</tr>
<tr>
<td><%= t('invoices.issued_for') %></td>
<td><%= @invoice.recipient %><br><%= @invoice.address %></td>
</tr>
<tr>
<td><%= t(:updated_by) %></td>
<td><%= @invoice.updated_by %></td>
</tr>
<% if @invoice.notes %>
<div class="item">
<div class="header"><%= t('invoices.notes') %></div>
<%= @invoice.notes %>
</div>
<tr>
<td><%= t('invoices.notes') %></td>
<td><%= @invoice.notes %></td>
</tr>
<% end %>
<% if @invoice.paid_at %>
<tr>
<td><%= t('invoices.paid_at') %></td>
<td><%= @invoice.paid_at %></td>
</tr>
<% end %>
</div>
<div>
<div class="header"><%= t('invoices.issuer') %></div>
<%= Setting.find_by(code: 'invoice_issuer').retrieve %>
<div class="header"><%= t('invoices.issue_date') %></div>
<%= @invoice.issue_date %>
<div class="header"><%= t('invoices.due_date') %></div>
<%= @invoice.due_date %>
<tr>
<td><%= t('invoices.issuer') %></td>
<td><%= Setting.find_by(code: 'invoice_issuer').retrieve %></td>
</tr>
<tr>
<td><%= t('invoices.issue_date') %></td>
<td><%= @invoice.issue_date %></td>
</tr>
<tr>
<td><%= t('invoices.due_date') %></td>
<td><%= @invoice.due_date %></td>
</tr>
<% if @invoice.paid_with_payment_order %>
<div class="item">
<div class="header"><%= t('invoices.paid_through') %></div>
<%= @invoice.paid_with_payment_order&.channel %>
</div>
<tr>
<td><%= t('invoices.paid_through') %></td>
<td><%= @invoice.paid_with_payment_order&.channel %></td>
</tr>
<% end %>
</div>
</div>
</tbody>
</table>
</div>
<div class="c-table c-table--sortable">
<h2><%= t('invoices.items') %></h2>

<div class="c-block">
<h2 class="c-block__title u-h3"><%= t('invoices.items') %></h2>
<% header_collection = [{column: nil, caption: '#', options: {}},
{ column: nil, caption: t('invoices.item'), options: { class: "" } },
{ column: nil, caption: '', options: { class: "" } },
{ column: nil, caption: t('invoices.price'), options: { class: "" } },] %>
<%= component 'common/table', header_collection:, options: { class: 'js-table-dt dataTable no-footer' } do %>
<%= component 'common/table', header_collection:, options: { class: 'table' } do %>
<%= tag.tbody class: 'contents' do %>
<% @invoice.items.each_with_index do |item, index| %>
<tr>
Expand All @@ -75,7 +96,7 @@
<tr>
<th scope="col"></th>
<th scope="col"><%= t('invoices.total') %></th>
<td></td>
<th></th>
<th scope="col"><%= t('offers.price_in_currency', price: @invoice.total + (@invoice.enable_deposit? ? @invoice.deposit : 0.0)) %></th>
</tr>
<% if @invoice.paid? || @invoice.partial_payments? %>
Expand Down Expand Up @@ -108,13 +129,16 @@
<% end %>
</tfoot>
<% end %>
<h2><%= t('payment_orders.title') %></h2>
</div>

<div class="c-block">
<h2 class="c-block__title u-h3"><%= t('payment_orders.title') %></h2>
<% header_collection = [{column: nil, caption: '#', options: {}},
{ column: nil, caption: t('payment_orders.channel'), options: { class: "" } },
{ column: nil, caption: t('payment_orders.status'), options: { class: "" } },
{ column: nil, caption: t('payment_orders.initiated'), options: { class: "" } },
{ column: nil, caption: t('payment_orders.response'), options: { class: "" } },] %>
<%= component 'common/table', header_collection:, options: { class: 'js-table-dt dataTable no-footer' } do %>
<%= component 'common/table', header_collection:, options: { class: 'table--black' } do %>
<%= tag.tbody class: 'contents' do %>
<% @payment_orders.each do |payment_order| %>
<tr>
Expand Down
1 change: 1 addition & 0 deletions config/locales/invoices.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ en:
paid_deposit_title: "Paid deposits"
pay_all: Pay all invoices
partial_payments_activated: "Allowed clients to make partial payments for this invoice"
partial_payments_deactivated: "Disallowed clients to make partial payments for this invoice"
allow_partial_payments: "Allow partial payments"
disallow_partial_payments: "Disallow partial payments"
amount_must_be_positive: "Amount must be greater than 0"
Expand Down
1 change: 1 addition & 0 deletions config/locales/invoices.et.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ et:
paid_deposit_title: Deposiidimaksed
pay_all: "Maksa kõik arved"
partial_payments_activated: "Lubatud klientidel teha selle arve osalisi makseid"
partial_payments_deactivated: "Keelatud klientidel teha selle arve osalisi makseid"
allow_partial_payments: "Luba osalisi makseid"
disallow_partial_payments: "Keela osalised maksed"
amount_must_be_positive: "Summa peab olema suurem kui 0"
Expand Down
Loading
Loading