dorsale 3.14.11 → 3.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/app/assets/javascripts/dorsale/dependencies.coffee +1 -1
  4. data/app/assets/javascripts/dorsale/engines/billing_machine.coffee.erb +14 -0
  5. data/app/assets/stylesheets/dorsale/engines/billing_machine.sass +4 -1
  6. data/app/controllers/dorsale/billing_machine/invoices_controller.rb +14 -9
  7. data/app/controllers/dorsale/billing_machine/quotations_controller.rb +14 -9
  8. data/app/controllers/dorsale/expense_gun/expenses_controller.rb +24 -34
  9. data/app/controllers/dorsale/flyboy/task_comments_controller.rb +2 -2
  10. data/app/filters/dorsale/expense_gun/small_data/filter_for_expenses.rb +5 -2
  11. data/app/helpers/dorsale/expense_gun/application_helper.rb +1 -1
  12. data/app/mailers/dorsale/flyboy/task_mailer.rb +2 -2
  13. data/app/models/dorsale/billing_machine/invoice.rb +2 -4
  14. data/app/models/dorsale/billing_machine/invoice_line.rb +1 -1
  15. data/app/models/dorsale/billing_machine/quotation.rb +1 -1
  16. data/app/models/dorsale/billing_machine/quotation_line.rb +1 -1
  17. data/app/models/dorsale/customer_vault/corporation.rb +11 -2
  18. data/app/models/dorsale/customer_vault/individual.rb +4 -2
  19. data/app/models/dorsale/customer_vault/person.rb +1 -1
  20. data/app/models/dorsale/expense_gun/expense.rb +7 -34
  21. data/app/policies/dorsale/expense_gun/expense_policy_helper.rb +9 -20
  22. data/app/services/dorsale/flyboy/task/snoozer.rb +1 -1
  23. data/app/sorters/dorsale/expense_gun/expenses_sorter.rb +8 -0
  24. data/app/uploaders/dorsale/image_uploader.rb +1 -1
  25. data/app/uploaders/dorsale/pdf_uploader.rb +1 -1
  26. data/app/views/dorsale/billing_machine/commons/_form.html.slim +2 -1
  27. data/app/views/dorsale/billing_machine/commons/_line_fields.html.slim +4 -0
  28. data/app/views/dorsale/expense_gun/expenses/_filters.html.slim +8 -0
  29. data/app/views/dorsale/expense_gun/expenses/_form.html.slim +3 -4
  30. data/app/views/dorsale/expense_gun/expenses/_list.html.slim +62 -20
  31. data/app/views/dorsale/expense_gun/expenses/_show_actions.html.slim +2 -12
  32. data/app/views/dorsale/expense_gun/expenses/_state_actions.html.slim +8 -0
  33. data/app/views/dorsale/expense_gun/expenses/index.html.slim +1 -1
  34. data/app/views/dorsale/flyboy/task_mailer/new_task.html.slim +1 -1
  35. data/app/views/dorsale/flyboy/task_mailer/term_email.html.slim +1 -1
  36. data/config/locales/billing_machine.fr.yml +1 -0
  37. data/config/locales/expense_gun.fr.yml +12 -10
  38. data/config/routes.rb +3 -4
  39. data/db/migrate/20210202100529_billing_machine_add_positions.rb +6 -0
  40. data/db/migrate/20210311131928_billing_machine_add_missing_unique_indexes.rb +6 -0
  41. data/db/migrate/20210506070548_expenses_change_states.rb +7 -0
  42. data/features/expense_gun_expenses.feature +0 -30
  43. data/features/step_definitions/customer_vault_people_steps.rb +1 -1
  44. data/features/step_definitions/expense_gun_expenses_steps.rb +1 -16
  45. data/lib/dorsale/engine.rb +0 -1
  46. data/lib/dorsale/version.rb +1 -1
  47. data/spec/controllers/dorsale/expense_gun/expenses_controller_spec.rb +66 -17
  48. data/spec/controllers/dorsale/flyboy/task_comments_controller_spec.rb +2 -2
  49. data/spec/factories/customer_vault_individuals.rb +13 -13
  50. data/spec/factories/expense_gun_categories.rb +3 -3
  51. data/spec/factories/expense_gun_expense_lines.rb +7 -7
  52. data/spec/factories/expense_gun_expenses.rb +3 -3
  53. data/spec/models/dorsale/expense_gun/expense_spec.rb +1 -125
  54. data/spec/pdfs/dorsale/billing_machine/invoice_multiple_vat_pdf_spec.rb +1 -1
  55. data/spec/pdfs/dorsale/billing_machine/invoice_single_vat_pdf_spec.rb +1 -1
  56. data/spec/pdfs/dorsale/billing_machine/quotation_multiple_vat_pdf_spec.rb +1 -1
  57. data/spec/pdfs/dorsale/billing_machine/quotation_single_vat_pdf_spec.rb +1 -1
  58. data/spec/rails_helper.rb +0 -1
  59. data/spec/routing/dorsale/expense_gun/expenses_routing_spec.rb +9 -14
  60. data/spec/services/dorsale/expense_gun/expense/copy_spec.rb +2 -2
  61. data/spec/sorters/dorsale/expense_gun/expenses_sorter_spec.rb +20 -0
  62. metadata +10 -35
  63. data/app/assets/javascripts/url.min.js +0 -1
  64. data/app/models/dorsale/customer_vault/corporation_data.rb +0 -10
  65. data/app/models/dorsale/customer_vault/individual_data.rb +0 -3
  66. data/app/models/dorsale/customer_vault/person_data.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6866c7560ef92fbd39d25e808a3839c2cd2cebc74f96032e822ec91da2d15d22
4
- data.tar.gz: 178783cfc18bcd2e657679d8aba7d03c03f5a1576d89c36811767fdf10d4d2a0
3
+ metadata.gz: 86af52038f7c9cfc24b17dbcf5229608296a7152f2e4565d3fd415d2dd88ce87
4
+ data.tar.gz: cd7c59ee287a99e1cac77068550f7a0d64451e164cb2e10855fd1dd2d9b5fb12
5
5
  SHA512:
6
- metadata.gz: 7c13fd4a88831a65793b92a20fe25008e53313d80c05e94cf10b96b12b5b15e315e679b00177f96f700028b9b7bcecbf361cb0e25d7196d2e6d6ab78e91cdaab
7
- data.tar.gz: ab777662670e599361601e3e4a052785f9208835b2170232e6da9fd72c74e7d6dbb99a2b65828d5432ff4df843370cc3ba908aee85d8f8f1c81ca0c1a4da9355
6
+ metadata.gz: 20bc75f4aa3210835d0b8ce2c6e7bb0b43ab7b2a496555df02fc1b6ef9983af553ad586170a5d67c729630905706d6ecea52340811781707520f71a47211e73a
7
+ data.tar.gz: 33809971e1f21d88f6a6d6d110a062cb94b18391dee6c667afa28adc9c7d9690d99806b783f02c8a0f427771e7d9f473b7a693cbba069f339005f5631426fa6d
data/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## Next version
4
4
 
5
+ # 3.19.0
6
+ - Change expenses state machine
7
+ - Change expenses list view
8
+
9
+ # 3.18.0
10
+ - Change uploaders `extension_whitelist` to `extension_allowlist`
11
+ - Rails 6.1 compatibility
12
+
13
+ ## 3.17.0
14
+ - Refactor CV models using stores
15
+ - Fix redirect after task comment create
16
+ - Add missing unique indexes on invoices and quotations
17
+
18
+ ## 3.16.0
19
+ - Allow to reorder BM lines (require Sorting.js + reimport migrations)
20
+ - Remove unused url.js
21
+
22
+ ## 3.15.0
23
+ - Fix Ruby 2.7 warnings
24
+ - Faker 2
25
+
5
26
  ## 3.14.11
6
27
  - Fix BM missing PDFs
7
28
 
@@ -4,11 +4,11 @@
4
4
  //= require bootstrap
5
5
  //= require cocoon
6
6
  //= require accounting
7
- //= require url.min
8
7
  //= require select2
9
8
  //= require select2_locale_fr
10
9
  //= require bootstrap-datepicker/core
11
10
  //= require bootstrap-datepicker/locales/bootstrap-datepicker.fr
12
11
  //= require Chart.bundle
13
12
  //= require chartkick
13
+ //= require Sortable
14
14
  //= require agilibox/all
@@ -77,6 +77,10 @@ BillingMachine.formatInputs = ->
77
77
  formatted_number = BillingMachine.num2str BillingMachine.str2num $(this).val()
78
78
  $(this).val formatted_number
79
79
 
80
+ BillingMachine.updatePositions = ->
81
+ i = 0
82
+ $("#billing_machine-form input[name*=position]").map -> this.value = (i = i + 1)
83
+
80
84
  # Empty number inputs on focus if value is 0
81
85
  $(document).on "focus", "#billing_machine-form input.number", ->
82
86
  $(this).val("") if BillingMachine.str2num($(this).val()) == 0
@@ -96,6 +100,7 @@ $(document).on "click", "#billing_machine-form a.delete", (e) ->
96
100
  $(document).on "turbolinks:load cocoon:after-insert", ->
97
101
  BillingMachine.formatInputs()
98
102
  BillingMachine.updateTotals()
103
+ BillingMachine.updatePositions()
99
104
 
100
105
  # Fix Cocoon bug
101
106
  $("#billing_machine-form .line textarea").map ->
@@ -106,3 +111,12 @@ $(document).on "keyup", "#billing_machine-form input.number", ->
106
111
 
107
112
  $(document).on "blur", "#billing_machine-form input.number", ->
108
113
  BillingMachine.formatInputs()
114
+
115
+ $(document).on "turbolinks:load", ->
116
+ $("#billing_machine-form tbody").map ->
117
+ container = this
118
+
119
+ new Sortable container,
120
+ handle: ".handle"
121
+ animation: 150
122
+ onSort: -> BillingMachine.updatePositions()
@@ -103,11 +103,14 @@
103
103
 
104
104
  th.actions,
105
105
  td.actions,
106
+ th.position,
107
+ td.position,
106
108
  padding: 0
107
109
  width: 2.5em
108
110
  text-align: center
109
111
 
110
- th.actions
112
+ th.actions,
113
+ th.position,
111
114
  border: none
112
115
 
113
116
  // disabled fields
@@ -157,15 +157,20 @@ class Dorsale::BillingMachine::InvoicesController < ::Dorsale::BillingMachine::A
157
157
  :advance,
158
158
  :due_date,
159
159
  :comments,
160
- :lines_attributes => [
161
- :_destroy,
162
- :id,
163
- :label,
164
- :quantity,
165
- :unit,
166
- :unit_price,
167
- :vat_rate,
168
- ],
160
+ :lines_attributes => line_permitted_params,
161
+ ]
162
+ end
163
+
164
+ def line_permitted_params
165
+ [
166
+ :_destroy,
167
+ :id,
168
+ :label,
169
+ :quantity,
170
+ :unit,
171
+ :unit_price,
172
+ :vat_rate,
173
+ :position,
169
174
  ]
170
175
  end
171
176
 
@@ -165,15 +165,20 @@ class Dorsale::BillingMachine::QuotationsController < ::Dorsale::BillingMachine:
165
165
  :comments,
166
166
  :vat_rate,
167
167
  :commercial_discount,
168
- :lines_attributes => [
169
- :_destroy,
170
- :id,
171
- :label,
172
- :quantity,
173
- :unit,
174
- :unit_price,
175
- :vat_rate,
176
- ],
168
+ :lines_attributes => line_permitted_params,
169
+ ]
170
+ end
171
+
172
+ def line_permitted_params
173
+ [
174
+ :_destroy,
175
+ :id,
176
+ :label,
177
+ :quantity,
178
+ :unit,
179
+ :unit_price,
180
+ :vat_rate,
181
+ :position,
177
182
  ]
178
183
  end
179
184
 
@@ -1,15 +1,5 @@
1
1
  class Dorsale::ExpenseGun::ExpensesController < Dorsale::ExpenseGun::ApplicationController
2
- before_action :set_expense, only: [
3
- :show,
4
- :edit,
5
- :update,
6
- :copy,
7
- :submit,
8
- :accept,
9
- :refuse,
10
- :cancel,
11
- ]
12
-
2
+ before_action :set_expense
13
3
  before_action :set_filters_variables, only: [:index]
14
4
 
15
5
  def index
@@ -18,7 +8,10 @@ class Dorsale::ExpenseGun::ExpensesController < Dorsale::ExpenseGun::Application
18
8
  @expenses ||= scope.all.preload(:user, :expense_lines)
19
9
  @filters ||= Dorsale::ExpenseGun::SmallData::FilterForExpenses.new(filters_jar)
20
10
  @expenses = @filters.apply(@expenses)
11
+ @expenses = Dorsale::ExpenseGun::ExpensesSorter.call(@expenses, params[:sort] ||= "-created_at")
21
12
  @expenses = @expenses.page(params[:page]).per(25)
13
+
14
+ @total_payback = @expenses.limit(nil).to_a.sum(&:total_employee_payback)
22
15
  end
23
16
 
24
17
  def new
@@ -34,7 +27,7 @@ class Dorsale::ExpenseGun::ExpensesController < Dorsale::ExpenseGun::Application
34
27
  @expense ||= scope.new(expense_params_for_create)
35
28
 
36
29
  if @expense.save
37
- flash[:success] = t("expense_gun.expense.messages.created")
30
+ set_succress_flash
38
31
  redirect_to dorsale.expense_gun_expense_path(@expense)
39
32
  else
40
33
  render :new
@@ -55,7 +48,7 @@ class Dorsale::ExpenseGun::ExpensesController < Dorsale::ExpenseGun::Application
55
48
  authorize @expense, :update?
56
49
 
57
50
  if @expense.update(expense_params_for_update)
58
- flash[:success] = t("expense_gun.expense.messages.updated")
51
+ set_succress_flash
59
52
  redirect_to dorsale.expense_gun_expense_path(@expense)
60
53
  else
61
54
  render :edit
@@ -71,50 +64,47 @@ class Dorsale::ExpenseGun::ExpensesController < Dorsale::ExpenseGun::Application
71
64
  render :new
72
65
  end
73
66
 
74
- def submit
75
- authorize @expense, :submit?
67
+ def go_to_pending
68
+ authorize @expense, :go_to_pending?
76
69
 
77
- @expense.go_to_submitted!
78
- flash[:success] = t("expense_gun.expense.messages.submitted")
70
+ @expense.update!(state: "pending")
71
+ set_succress_flash
79
72
  redirect_to dorsale.expense_gun_expenses_path
80
73
  end
81
74
 
82
- def accept
83
- authorize @expense, :accept?
84
-
85
- @expense.go_to_accepted!
86
- flash[:success] = t("expense_gun.expense.messages.accepted")
87
- redirect_to dorsale.expense_gun_expense_path(@expense)
88
- end
75
+ def go_to_paid
76
+ authorize @expense, :go_to_paid?
89
77
 
90
- def refuse
91
- authorize @expense, :refuse?
92
-
93
- @expense.go_to_refused!
94
- flash[:success] = t("expense_gun.expense.messages.refused")
78
+ @expense.update!(state: "paid")
79
+ set_succress_flash
95
80
  redirect_to dorsale.expense_gun_expenses_path
96
81
  end
97
82
 
98
- def cancel
99
- authorize @expense, :cancel?
83
+ def go_to_canceled
84
+ authorize @expense, :go_to_canceled?
100
85
 
101
- @expense.go_to_canceled!
102
- flash[:success] = t("expense_gun.expense.messages.canceled")
86
+ @expense.update!(state: "canceled")
87
+ set_succress_flash
103
88
  redirect_to dorsale.expense_gun_expenses_path
104
89
  end
105
90
 
106
91
  private
107
92
 
93
+ def set_succress_flash
94
+ flash.notice = t("expense_gun.expense.messages.#{action_name}_ok")
95
+ end
96
+
108
97
  def model
109
98
  ::Dorsale::ExpenseGun::Expense
110
99
  end
111
100
 
112
101
  def set_expense
113
- @expense = scope.find(params[:id])
102
+ @expense = scope.find(params[:id]) if params.key?(:id)
114
103
  end
115
104
 
116
105
  def permitted_params
117
106
  [
107
+ :state,
118
108
  :name,
119
109
  :date,
120
110
  :expense_lines_attributes => [
@@ -19,9 +19,9 @@ class Dorsale::Flyboy::TaskCommentsController < ::Dorsale::Flyboy::ApplicationCo
19
19
 
20
20
  def back_url
21
21
  task_path = flyboy_task_path(@task)
22
- back_url = super
22
+ back_url = super.to_s
23
23
 
24
- if back_url.to_s.start_with?(task_path)
24
+ if back_url == task_path || back_url.start_with?(task_path + "?")
25
25
  back_url
26
26
  else
27
27
  task_path
@@ -1,6 +1,9 @@
1
1
  class Dorsale::ExpenseGun::SmallData::FilterForExpenses < ::Agilibox::SmallData::Filter
2
2
  STRATEGIES = {
3
- "expense_state" => ::Agilibox::SmallData::FilterStrategyByKeyValue.new("state"),
4
- "expense_user_id" => ::Agilibox::SmallData::FilterStrategyByKeyValue.new("user_id"),
3
+ "expense_state" => ::Agilibox::SmallData::FilterStrategyByKeyValue.new("state"),
4
+ "expense_user_id" => ::Agilibox::SmallData::FilterStrategyByKeyValue.new("user_id"),
5
+ "expense_time_period" => ::Agilibox::SmallData::FilterStrategyByDatePeriod.new(:date),
6
+ "expense_date_begin" => ::Agilibox::SmallData::FilterStrategyByDateBegin.new(:date),
7
+ "expense_date_end" => ::Agilibox::SmallData::FilterStrategyByDateEnd.new(:date),
5
8
  }
6
9
  end
@@ -1,6 +1,6 @@
1
1
  module Dorsale::ExpenseGun::ApplicationHelper
2
2
  def expense_states_for_filters_select
3
- Dorsale::ExpenseGun::Expense.aasm.states.map do |state|
3
+ Dorsale::ExpenseGun::Expense::STATES.map do |state|
4
4
  [
5
5
  Dorsale::ExpenseGun::Expense.t("state.#{state}"),
6
6
  state,
@@ -11,7 +11,7 @@ class Dorsale::Flyboy::TaskMailer < ::Dorsale::ApplicationMailer
11
11
 
12
12
  mail(
13
13
  :to => task.owner.email,
14
- :subject => t("task_mailer.new_task.subject", @locals),
14
+ :subject => t("task_mailer.new_task.subject", **@locals),
15
15
  )
16
16
  end
17
17
 
@@ -26,7 +26,7 @@ class Dorsale::Flyboy::TaskMailer < ::Dorsale::ApplicationMailer
26
26
 
27
27
  mail(
28
28
  :to => task.owner.email,
29
- :subject => t("task_mailer.term_email.subject", @locals),
29
+ :subject => t("task_mailer.term_email.subject", **@locals),
30
30
  )
31
31
  end
32
32
  end
@@ -55,7 +55,7 @@ class Dorsale::BillingMachine::Invoice < ::Dorsale::ApplicationRecord
55
55
  lines.each(&:update_total)
56
56
  apply_vat_rate_to_lines
57
57
 
58
- lines_sum = lines.map(&:total).sum.round(2)
58
+ lines_sum = lines.sum(&:total).round(2)
59
59
 
60
60
  self.total_excluding_taxes = lines_sum - commercial_discount
61
61
 
@@ -109,9 +109,7 @@ class Dorsale::BillingMachine::Invoice < ::Dorsale::ApplicationRecord
109
109
  def payment_status
110
110
  if paid?
111
111
  :paid
112
- elsif due_date.nil?
113
- :on_alert
114
- elsif Date.current >= due_date + 15
112
+ elsif due_date.nil? || Date.current >= due_date + 15
115
113
  :on_alert
116
114
  elsif Date.current > due_date
117
115
  :late
@@ -6,7 +6,7 @@ class Dorsale::BillingMachine::InvoiceLine < ::Dorsale::ApplicationRecord
6
6
  validates :invoice, presence: true
7
7
 
8
8
  default_scope -> {
9
- order(created_at: :asc)
9
+ order(position: :asc, created_at: :asc, id: :asc)
10
10
  }
11
11
 
12
12
  before_validation :update_total
@@ -61,7 +61,7 @@ class Dorsale::BillingMachine::Quotation < ::Dorsale::ApplicationRecord
61
61
  lines.each(&:update_total)
62
62
  apply_vat_rate_to_lines
63
63
 
64
- lines_sum = lines.map(&:total).sum
64
+ lines_sum = lines.sum(&:total)
65
65
 
66
66
  self.total_excluding_taxes = lines_sum - commercial_discount
67
67
 
@@ -6,7 +6,7 @@ class Dorsale::BillingMachine::QuotationLine < ::Dorsale::ApplicationRecord
6
6
  validates :quotation, presence: true
7
7
 
8
8
  default_scope -> {
9
- order(:created_at => :asc)
9
+ order(position: :asc, created_at: :asc, id: :asc)
10
10
  }
11
11
 
12
12
  before_validation :update_total
@@ -1,6 +1,15 @@
1
1
  class Dorsale::CustomerVault::Corporation < Dorsale::CustomerVault::Person
2
- serialize :data, Dorsale::CustomerVault::CorporationData
3
- def_delegators :data, *Dorsale::CustomerVault::CorporationData.methods_to_delegate
2
+ data_attributes = %i(
3
+ legal_form
4
+ immatriculation_number
5
+ naf
6
+ european_union_vat_number
7
+ societe_com
8
+ capital
9
+ revenue
10
+ number_of_employees
11
+ )
12
+ store :data, accessors: data_attributes, coder: JSON
4
13
 
5
14
  validates :corporation_name, presence: true
6
15
  has_many :individuals, dependent: :nullify
@@ -1,6 +1,8 @@
1
1
  class Dorsale::CustomerVault::Individual < Dorsale::CustomerVault::Person
2
- serialize :data, Dorsale::CustomerVault::IndividualData
3
- def_delegators :data, *Dorsale::CustomerVault::IndividualData.methods_to_delegate
2
+ data_attributes = %i(
3
+ title
4
+ )
5
+ store :data, accessors: data_attributes, coder: JSON
4
6
 
5
7
  validates :first_name, presence: true
6
8
  validates :last_name, presence: true
@@ -10,7 +10,7 @@ class Dorsale::CustomerVault::Person < ::Dorsale::ApplicationRecord
10
10
  end
11
11
 
12
12
  def verify_class
13
- if self.class == ::Dorsale::CustomerVault::Person
13
+ if instance_of?(Dorsale::CustomerVault::Person)
14
14
  # self.abstract_class does not work with STI
15
15
  raise "Cannot directly instantiate Person class"
16
16
  end
@@ -1,6 +1,7 @@
1
1
  class Dorsale::ExpenseGun::Expense < ::Dorsale::ApplicationRecord
2
2
  self.table_name = "dorsale_expense_gun_expenses"
3
- include AASM
3
+
4
+ STATES = %w(draft pending paid canceled)
4
5
 
5
6
  has_many :expense_lines, inverse_of: :expense, dependent: :destroy, class_name: "Dorsale::ExpenseGun::ExpenseLine"
6
7
 
@@ -12,6 +13,7 @@ class Dorsale::ExpenseGun::Expense < ::Dorsale::ApplicationRecord
12
13
  belongs_to :user
13
14
  validates :user, presence: true
14
15
 
16
+ validates :state, presence: true, inclusion: {in: STATES}
15
17
  validates :name, presence: true
16
18
  validates :date, presence: true
17
19
 
@@ -24,51 +26,22 @@ class Dorsale::ExpenseGun::Expense < ::Dorsale::ApplicationRecord
24
26
  }
25
27
 
26
28
  def assign_default_values
29
+ assign_default :state, STATES.first
27
30
  assign_default :date, Date.current
28
31
  end
29
32
 
30
33
  # Sum of line amounts
31
34
  def total_all_taxes
32
- expense_lines.map(&:total_all_taxes).sum
35
+ expense_lines.sum(&:total_all_taxes)
33
36
  end
34
37
 
35
38
  # Sum of line emplee payback
36
39
  def total_employee_payback
37
- expense_lines.map(&:employee_payback).sum
40
+ expense_lines.sum(&:employee_payback)
38
41
  end
39
42
 
40
43
  # Sum of deductible deductible vat
41
44
  def total_vat_deductible
42
- expense_lines.map(&:total_vat_deductible).sum
43
- end
44
-
45
- delegate :current_state, to: :aasm
46
-
47
- aasm(column: :state, whiny_transitions: false) do
48
- state :draft, initial: true
49
- state :submitted
50
- state :accepted
51
- state :refused
52
- state :canceled
53
-
54
- event :go_to_submitted do
55
- transitions from: :draft, to: :submitted
56
- end
57
-
58
- event :go_to_accepted do
59
- transitions from: :submitted, to: :accepted
60
- end
61
-
62
- event :go_to_refused do
63
- transitions from: :submitted, to: :refused
64
- end
65
-
66
- event :go_to_canceled do
67
- transitions from: [:draft, :submitted, :accepted], to: :canceled
68
- end
69
- end
70
-
71
- def may_edit?
72
- current_state == :draft
45
+ expense_lines.sum(&:total_vat_deductible)
73
46
  end
74
47
  end