dorsale 3.14.9 → 3.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -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/customer_vault/events_controller.rb +0 -2
  9. data/app/controllers/dorsale/flyboy/task_comments_controller.rb +2 -2
  10. data/app/mailers/dorsale/flyboy/task_mailer.rb +2 -2
  11. data/app/models/dorsale/billing_machine/invoice.rb +2 -4
  12. data/app/models/dorsale/billing_machine/invoice_line.rb +1 -1
  13. data/app/models/dorsale/billing_machine/quotation.rb +1 -2
  14. data/app/models/dorsale/billing_machine/quotation_line.rb +1 -1
  15. data/app/models/dorsale/customer_vault/corporation.rb +11 -2
  16. data/app/models/dorsale/customer_vault/individual.rb +4 -2
  17. data/app/models/dorsale/customer_vault/person.rb +7 -7
  18. data/app/pdfs/dorsale/billing_machine/invoice_single_vat_pdf.rb +2 -2
  19. data/app/policies/dorsale/application_policy.rb +1 -0
  20. data/app/services/dorsale/billing_machine/invoice/copy.rb +1 -0
  21. data/app/services/dorsale/billing_machine/pdf_file_generator.rb +1 -7
  22. data/app/services/dorsale/billing_machine/quotation/copy.rb +1 -0
  23. data/app/services/dorsale/billing_machine/quotation/to_invoice.rb +1 -0
  24. data/app/services/dorsale/expense_gun/expense/copy.rb +1 -0
  25. data/app/services/dorsale/flyboy/task/copy.rb +1 -0
  26. data/app/services/dorsale/flyboy/task/snoozer.rb +1 -0
  27. data/app/services/dorsale/tag_list_for_model.rb +1 -0
  28. data/app/views/dorsale/billing_machine/commons/_form.html.slim +2 -1
  29. data/app/views/dorsale/billing_machine/commons/_line_fields.html.slim +4 -0
  30. data/app/views/dorsale/billing_machine/invoices/show.pdf.ruby +1 -1
  31. data/app/views/dorsale/billing_machine/quotations/show.pdf.ruby +1 -1
  32. data/app/views/dorsale/flyboy/task_mailer/new_task.html.slim +1 -1
  33. data/app/views/dorsale/flyboy/task_mailer/term_email.html.slim +1 -1
  34. data/config/locales/billing_machine.fr.yml +1 -0
  35. data/db/migrate/20210202100529_billing_machine_add_positions.rb +6 -0
  36. data/db/migrate/20210311131928_billing_machine_add_missing_unique_indexes.rb +6 -0
  37. data/features/step_definitions/billing_machine_payment_terms_steps.rb +1 -1
  38. data/features/step_definitions/billing_machine_quotations_steps.rb +1 -1
  39. data/features/step_definitions/customer_vault_activity_types_steps.rb +1 -1
  40. data/features/step_definitions/customer_vault_origins_steps.rb +1 -1
  41. data/features/step_definitions/customer_vault_people_steps.rb +1 -1
  42. data/features/step_definitions/customer_vault_search_steps.rb +10 -10
  43. data/features/step_definitions/expense_gun_categories_steps.rb +1 -1
  44. data/lib/dorsale/version.rb +1 -1
  45. data/spec/controllers/dorsale/flyboy/task_comments_controller_spec.rb +2 -2
  46. data/spec/factories/customer_vault_individuals.rb +13 -13
  47. data/spec/factories/expense_gun_categories.rb +3 -3
  48. data/spec/factories/expense_gun_expense_lines.rb +7 -7
  49. data/spec/factories/expense_gun_expenses.rb +3 -3
  50. data/spec/pdfs/dorsale/billing_machine/invoice_multiple_vat_pdf_spec.rb +1 -1
  51. data/spec/pdfs/dorsale/billing_machine/invoice_single_vat_pdf_spec.rb +1 -1
  52. data/spec/pdfs/dorsale/billing_machine/quotation_multiple_vat_pdf_spec.rb +1 -1
  53. data/spec/pdfs/dorsale/billing_machine/quotation_single_vat_pdf_spec.rb +1 -1
  54. data/spec/rails_helper.rb +0 -1
  55. metadata +5 -21
  56. data/app/assets/javascripts/url.min.js +0 -1
  57. data/app/models/dorsale/customer_vault/corporation_data.rb +0 -10
  58. data/app/models/dorsale/customer_vault/individual_data.rb +0 -3
  59. 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: c02356f6d8c0cf4484b3c5bbf8ae14b4afb5807b79a836c3ac3def7fe4f0d795
4
- data.tar.gz: 10e1416b942207884fc2a84665285e6a5ebb9d73fe5d65a69057f89d05ac75fa
3
+ metadata.gz: edb8363b4a987b737cfba9c432a65fd5c64fbb72690c51f6ea5da99c195430a6
4
+ data.tar.gz: 9b88ffbea03b8971f2a853c5dfcbe6387670ec7b69d8601d68ab295ba425364c
5
5
  SHA512:
6
- metadata.gz: ad1c5adb07688951372ec42e57c85f9487c06257827dcf0e712ab3a87794c9c9ac5e6fe6ba09115fe3813e55ceba36b56dc871729e5aead840b3815af4a8b3a8
7
- data.tar.gz: 90da6df14ad83c78ea0abe031686ea1f9cbbdb3750005c669c19f89875b7ea77a9fce70c4bfbdc9dd7f28e28f95b954ef85395c8422b86148c9bbeefffeeed1d
6
+ metadata.gz: c84800985f5243887825313437907d6a40d2ab5398e7c78de903d404a9c3d5e1d01e6bed9c7cee4fe57f15af26d0aa0c1950ede73946dd3d3f8c14a7ce20a6e1
7
+ data.tar.gz: 373d7d5e133bcb61443e8defed065177fb6e82fc56bc7424abbb110f3632d51a07a24df569f96d2b336206339a2774d26c206d5b1ff6e6862f6d5b63baa061fb
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  ## Next version
4
4
 
5
+ ## 3.17.0
6
+ - Refactor CV models using stores
7
+ - Fix redirect after task comment create
8
+ - Add missing unique indexes on invoices and quotations
9
+
10
+ ## 3.16.0
11
+ - Allow to reorder BM lines (require Sorting.js + reimport migrations)
12
+ - Remove unused url.js
13
+
14
+ ## 3.15.0
15
+ - Fix Ruby 2.7 warnings
16
+ - Faker 2
17
+
18
+ ## 3.14.11
19
+ - Fix BM missing PDFs
20
+
21
+ ## 3.14.10
22
+ - Change BillingMachine PDF filenames
23
+ - Fix CustomerVault layout
24
+
5
25
  ## 3.14.9
6
26
  - Create corporation from individual form
7
27
  - Quotations: add draft state
@@ -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,8 +1,6 @@
1
1
  class Dorsale::CustomerVault::EventsController < ::Dorsale::CustomerVault::ApplicationController
2
2
  before_action :set_objects
3
3
 
4
- layout -> { action_name == "index" ? nil : false }
5
-
6
4
  def index
7
5
  authorize model, :list?
8
6
 
@@ -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
@@ -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
@@ -22,6 +22,8 @@ class Dorsale::BillingMachine::Invoice < ::Dorsale::ApplicationRecord
22
22
  :invoice
23
23
  end
24
24
 
25
+ after_initialize :assign_default_dates
26
+ before_save :update_totals
25
27
  before_create :assign_unique_index
26
28
  before_create :assign_tracking_id
27
29
 
@@ -43,15 +45,11 @@ class Dorsale::BillingMachine::Invoice < ::Dorsale::ApplicationRecord
43
45
  assign_default :paid, false
44
46
  end
45
47
 
46
- after_initialize :assign_default_dates
47
-
48
48
  def assign_default_dates
49
49
  assign_default :date, Date.current
50
50
  assign_default :due_date, Date.current + 30.days
51
51
  end
52
52
 
53
- before_save :update_totals
54
-
55
53
  def update_totals
56
54
  assign_default_values
57
55
  lines.each(&:update_total)
@@ -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
@@ -33,6 +33,7 @@ class Dorsale::BillingMachine::Quotation < ::Dorsale::ApplicationRecord
33
33
  :quotation
34
34
  end
35
35
 
36
+ before_save :update_totals
36
37
  before_create :assign_unique_index
37
38
  before_create :assign_tracking_id
38
39
 
@@ -55,8 +56,6 @@ class Dorsale::BillingMachine::Quotation < ::Dorsale::ApplicationRecord
55
56
  assign_default :total_excluding_taxes, 0
56
57
  end
57
58
 
58
- before_save :update_totals
59
-
60
59
  def update_totals
61
60
  assign_default_values
62
61
  lines.each(&:update_total)
@@ -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
@@ -9,8 +9,6 @@ class Dorsale::CustomerVault::Person < ::Dorsale::ApplicationRecord
9
9
  Dorsale::CustomerVault::PersonPolicy
10
10
  end
11
11
 
12
- after_initialize :verify_class
13
-
14
12
  def verify_class
15
13
  if self.class == ::Dorsale::CustomerVault::Person
16
14
  # self.abstract_class does not work with STI
@@ -30,6 +28,13 @@ class Dorsale::CustomerVault::Person < ::Dorsale::ApplicationRecord
30
28
  belongs_to :activity_type, class_name: "Dorsale::CustomerVault::ActivityType"
31
29
  belongs_to :origin, class_name: "Dorsale::CustomerVault::Origin"
32
30
 
31
+ validate :validate_taken_emails
32
+
33
+ after_initialize :verify_class
34
+ after_initialize :build_address, if: proc { new_record? && address.nil? }
35
+
36
+ before_validation :build_address, if: proc { address.nil? }
37
+
33
38
  after_destroy :destroy_links
34
39
 
35
40
  default_scope -> {
@@ -50,9 +55,6 @@ class Dorsale::CustomerVault::Person < ::Dorsale::ApplicationRecord
50
55
 
51
56
  scope :having_email, -> (email) { where("email = :e OR :e = ANY (secondary_emails)", e: email) }
52
57
 
53
- after_initialize :build_address, if: proc { new_record? && address.nil? }
54
- before_validation :build_address, if: proc { address.nil? }
55
-
56
58
  def taken_emails
57
59
  taken_emails = {}
58
60
  ([email] + secondary_emails).select(&:present?).each do |e|
@@ -62,8 +64,6 @@ class Dorsale::CustomerVault::Person < ::Dorsale::ApplicationRecord
62
64
  taken_emails
63
65
  end
64
66
 
65
- validate :validate_taken_emails
66
-
67
67
  def validate_taken_emails
68
68
  return if taken_emails.empty?
69
69
 
@@ -177,11 +177,11 @@ class Dorsale::BillingMachine::InvoiceSingleVatPdf < Dorsale::ApplicationPdf
177
177
  end
178
178
 
179
179
  def has_advance
180
- main_document.try(:advance) && main_document.advance != 0.0
180
+ main_document.try(:advance) && main_document.advance.to_d != 0.0.to_d
181
181
  end
182
182
 
183
183
  def has_discount
184
- main_document.try(:commercial_discount) && main_document.commercial_discount != 0.0
184
+ main_document.try(:commercial_discount) && main_document.commercial_discount.to_d != 0.0.to_d
185
185
  end
186
186
 
187
187
  def build_table
@@ -19,6 +19,7 @@ class Dorsale::ApplicationPolicy
19
19
  end
20
20
 
21
21
  def self.inherited(klass)
22
+ super(klass)
22
23
  klass.define_subject_accessor!
23
24
  end
24
25
 
@@ -2,6 +2,7 @@ class Dorsale::BillingMachine::Invoice::Copy < ::Dorsale::Service
2
2
  attr_accessor :invoice, :copy
3
3
 
4
4
  def initialize(invoice)
5
+ super()
5
6
  @invoice = invoice
6
7
  end
7
8
 
@@ -2,14 +2,8 @@ class Dorsale::BillingMachine::PdfFileGenerator < Dorsale::Service
2
2
  attr_reader :document
3
3
 
4
4
  def initialize(document)
5
+ super()
5
6
  @document = document
6
-
7
- # I have no idea why I need to do that,
8
- # if I don't do that, CarrierWare do not stores the file.
9
- # The reload() method don't work either.
10
- # The problem appears only on server, not in console.
11
- # I think CarrierWave do not work anymore after first save.
12
- @document = document.class.find(document.id) if document.persisted?
13
7
  end
14
8
 
15
9
  def call
@@ -2,6 +2,7 @@ class Dorsale::BillingMachine::Quotation::Copy < ::Dorsale::Service
2
2
  attr_accessor :quotation, :copy
3
3
 
4
4
  def initialize(quotation)
5
+ super()
5
6
  @quotation = quotation
6
7
  end
7
8
 
@@ -2,6 +2,7 @@ class Dorsale::BillingMachine::Quotation::ToInvoice < ::Dorsale::Service
2
2
  attr_accessor :quotation, :invoice
3
3
 
4
4
  def initialize(quotation)
5
+ super()
5
6
  @quotation = quotation
6
7
  end
7
8
 
@@ -2,6 +2,7 @@ class Dorsale::ExpenseGun::Expense::Copy < ::Dorsale::Service
2
2
  attr_accessor :expense, :copy
3
3
 
4
4
  def initialize(expense)
5
+ super()
5
6
  @expense = expense
6
7
  end
7
8
 
@@ -2,6 +2,7 @@ class Dorsale::Flyboy::Task::Copy < ::Dorsale::Service
2
2
  attr_accessor :task, :copy
3
3
 
4
4
  def initialize(task)
5
+ super()
5
6
  @task = task
6
7
  end
7
8
 
@@ -2,6 +2,7 @@ class Dorsale::Flyboy::Task::Snoozer < ::Dorsale::Service
2
2
  attr_reader :task
3
3
 
4
4
  def initialize(task)
5
+ super()
5
6
  @task = task
6
7
  end
7
8
 
@@ -2,6 +2,7 @@ class Dorsale::TagListForModel < ::Dorsale::Service
2
2
  attr_reader :model
3
3
 
4
4
  def initialize(model)
5
+ super()
5
6
  @model = model
6
7
  end
7
8
 
@@ -21,6 +21,7 @@
21
21
  table#lines-table
22
22
  thead
23
23
  tr
24
+ th.position
24
25
  th.actions
25
26
  th.line-label = Dorsale::BillingMachine::InvoiceLine.t(:label)
26
27
  th.line-quantity = Dorsale::BillingMachine::InvoiceLine.t(:quantity)
@@ -32,7 +33,7 @@
32
33
 
33
34
  tbody
34
35
  = f.simple_fields_for :lines do |lf|
35
- = render "dorsale/billing_machine/invoices/line_fields", f: lf
36
+ = render "dorsale/billing_machine/#{document.document_type}s/line_fields", f: lf
36
37
 
37
38
  .row
38
39
  .col-sm-6
@@ -1,4 +1,8 @@
1
1
  tr.line
2
+ td.position
3
+ = icon(:arrows_alt, class: "handle")
4
+ = f.hidden_field :position
5
+
2
6
  td.actions
3
7
  a.delete href="#"
4
8
  span.fa.fa-fw.fa-trash
@@ -1,7 +1,7 @@
1
1
  filename = [
2
2
  @invoice.t.capitalize,
3
3
  @invoice.tracking_id,
4
- @invoice.customer.try(:short_name),
4
+ @invoice.customer.to_s.tr(" ", "_"),
5
5
  ].join("_").concat(".pdf")
6
6
 
7
7
  response.headers["Content-Disposition"] = %(inline; filename="#{filename}")
@@ -1,7 +1,7 @@
1
1
  filename = [
2
2
  @quotation.t.capitalize,
3
3
  @quotation.tracking_id,
4
- @quotation.customer.try(:short_name),
4
+ @quotation.customer.to_s.tr(" ", "_"),
5
5
  ].join("_").concat(".pdf")
6
6
 
7
7
  response.headers["Content-Disposition"] = %(inline; filename="#{filename}")
@@ -1 +1 @@
1
- p == lf2br t("task_mailer.new_task.body", @locals)
1
+ p == lf2br t("task_mailer.new_task.body", **@locals)
@@ -1 +1 @@
1
- p == lf2br t("task_mailer.term_email.body", @locals)
1
+ p == lf2br t("task_mailer.term_email.body", **@locals)
@@ -25,6 +25,7 @@ fr:
25
25
  expires_at: "Date d'expiration"
26
26
  balance: "Reste à payer"
27
27
  pdf_file: "Fichier PDF"
28
+ position: "Position"
28
29
 
29
30
  activerecord:
30
31
  models:
@@ -0,0 +1,6 @@
1
+ class BillingMachineAddPositions < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :dorsale_billing_machine_invoice_lines, :position, :integer, null: false, default: 0
4
+ add_column :dorsale_billing_machine_quotation_lines, :position, :integer, null: false, default: 0
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class BillingMachineAddMissingUniqueIndexes < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_index :dorsale_billing_machine_invoices, :unique_index, unique: true
4
+ add_index :dorsale_billing_machine_quotations, :unique_index, unique: true
5
+ end
6
+ end
@@ -28,7 +28,7 @@ When(/^the user edits the payment_term$/) do
28
28
  find(".link_update").click
29
29
  end
30
30
 
31
- Then(/^the current payment_term's label should be pre\-filled$/) do
31
+ Then(/^the current payment_term's label should be pre-filled$/) do
32
32
  expect(page).to have_field("billing_machine_payment_term_label", with: @payment_term.label)
33
33
  end
34
34
 
@@ -58,7 +58,7 @@ When(/^the quotation line shows the right date$/) do
58
58
  expect(page).to have_selector ".date", text: I18n.l(@quotation.date)
59
59
  end
60
60
 
61
- When(/^the quotation line shows the right traking\-id$/) do
61
+ When(/^the quotation line shows the right traking-id$/) do
62
62
  expect(page).to have_selector ".tracking_id", text: @quotation.tracking_id
63
63
  end
64
64
 
@@ -28,7 +28,7 @@ When(/^I edit the activity type$/) do
28
28
  find(".link_update").click
29
29
  end
30
30
 
31
- Then(/^the current activity type's name should be pre\-filled$/) do
31
+ Then(/^the current activity type's name should be pre-filled$/) do
32
32
  expect(page).to have_field("activity_type_name", with: @activity_type.name)
33
33
  end
34
34
 
@@ -28,7 +28,7 @@ When(/^I edit the origin$/) do
28
28
  find(".link_update").click
29
29
  end
30
30
 
31
- Then(/^the current origin's name should be pre\-filled$/) do
31
+ Then(/^the current origin's name should be pre-filled$/) do
32
32
  expect(page).to have_field("origin_name", with: @origin.name)
33
33
  end
34
34
 
@@ -7,7 +7,7 @@ Then(/^the file is downloaded$/) do
7
7
  end
8
8
 
9
9
  Given(/^a very long comment on this person$/) do
10
- text = Faker::Lorem.paragraph(30)
10
+ text = Faker::Lorem.paragraph(sentence_count: 30)
11
11
  @comment = create(:customer_vault_event_comment, person: @person, text: text)
12
12
  end
13
13
 
@@ -1,48 +1,48 @@
1
- Lorsqu(/^he go to the people list$/) do
1
+ When(/^he go to the people list$/) do
2
2
  visit dorsale.customer_vault_people_path
3
3
  end
4
4
 
5
- Etantdonné(/^existing individuals$/) do
5
+ Given(/^existing individuals$/) do
6
6
  @individual1 = create(:customer_vault_individual, first_name: "Jean", last_name: "DUPONT")
7
7
  @individual2 = create(:customer_vault_individual, first_name: "Laurent", last_name: "DURAND")
8
8
  end
9
9
 
10
- Etantdonné(/^existing corporations$/) do
10
+ Given(/^existing corporations$/) do
11
11
  @corporation1 = create(:customer_vault_corporation, name: "aaa", email: "contact@aaa.com")
12
12
  @corporation2 = create(:customer_vault_corporation, name: "zzz", email: "contact@zzz.com")
13
13
  end
14
14
 
15
- Lorsqu(/^he search an individual by first name$/) do
15
+ When(/^he search an individual by first name$/) do
16
16
  fill_in "q", with: "Jean"
17
17
  find(".search-submit").click
18
18
  end
19
19
 
20
- Alors(/^this individual appear in search results$/) do
20
+ Then(/^this individual appear in search results$/) do
21
21
  expect(page).to have_content "Jean"
22
22
  expect(page).to have_content "DUPONT"
23
23
  end
24
24
 
25
- Alors(/^other individuals do not appear in search results$/) do
25
+ Then(/^other individuals do not appear in search results$/) do
26
26
  expect(page).to have_no_content "Laurent"
27
27
  expect(page).to have_no_content "DURAND"
28
28
  end
29
29
 
30
- Lorsqu(/^he search an individual by last name$/) do
30
+ When(/^he search an individual by last name$/) do
31
31
  fill_in "q", with: "DUPONT"
32
32
  find(".search-submit").click
33
33
  end
34
34
 
35
- Lorsqu(/^he search a corporation by name$/) do
35
+ When(/^he search a corporation by name$/) do
36
36
  fill_in "q", with: "aaa"
37
37
  find(".search-submit").click
38
38
  end
39
39
 
40
- Alors(/^this corporation appear in search results$/) do
40
+ Then(/^this corporation appear in search results$/) do
41
41
  expect(page).to have_content "aaa"
42
42
  expect(page).to have_content "contact@aaa.com"
43
43
  end
44
44
 
45
- Alors(/^other corporations do not appear in search results$/) do
45
+ Then(/^other corporations do not appear in search results$/) do
46
46
  expect(page).to have_no_content "zzz"
47
47
  expect(page).to have_no_content "contact@zzz.com"
48
48
  end
@@ -28,7 +28,7 @@ When(/^I edit the expense category$/) do
28
28
  find(".link_update").click
29
29
  end
30
30
 
31
- Then(/^the current expense category's label should be pre\-filled$/) do
31
+ Then(/^the current expense category's label should be pre-filled$/) do
32
32
  expect(page).to have_field("category_name", with: @category.name)
33
33
  end
34
34
 
@@ -1,3 +1,3 @@
1
1
  module Dorsale
2
- VERSION = "3.14.9"
2
+ VERSION = "3.17.0"
3
3
  end
@@ -18,7 +18,7 @@ describe Dorsale::Flyboy::TaskCommentsController, type: :controller do
18
18
  expect(assigns(:task_comment).persisted?).to be true
19
19
  end
20
20
 
21
- it "should redirect to referrer if referrer is task" do
21
+ it "should redirect to referrer if referrer is task show" do
22
22
  url = flyboy_task_path(task) + "?sort=xxx"
23
23
  request.env["HTTP_REFERER"] = url
24
24
  post :create, params: valid_params
@@ -26,7 +26,7 @@ describe Dorsale::Flyboy::TaskCommentsController, type: :controller do
26
26
  end
27
27
 
28
28
  it "should redirect to task if referrer is not task" do
29
- url = "/anywhere"
29
+ url = flyboy_task_path(task) + "/some-action"
30
30
  request.env["HTTP_REFERER"] = url
31
31
  post :create, params: valid_params
32
32
  expect(response).to redirect_to flyboy_task_path(task)
@@ -1,17 +1,17 @@
1
1
  FactoryBot.define do
2
2
  factory :customer_vault_individual, class: ::Dorsale::CustomerVault::Individual do
3
- origin { create(:customer_vault_origin) }
4
- first_name { Faker::Name.first_name }
5
- last_name { Faker::Name.last_name }
6
- short_name { "SN" }
7
- email { Faker::Internet.email("#{first_name} #{last_name}") }
8
- title { "Individual-Title" }
9
- twitter { "#{first_name}#{last_name}" }
10
- www { Faker::Internet.url }
11
- context { "Individual-Context" }
12
- phone { "01 23 xx xx xx" }
13
- fax { "09 xx xx xx xx" }
14
- mobile { "06 xx xx xx xx" }
15
- address { build(:dorsale_address) }
3
+ origin { create(:customer_vault_origin) }
4
+ first_name { Faker::Name.first_name }
5
+ last_name { Faker::Name.last_name }
6
+ short_name { "SN" }
7
+ email { Faker::Internet.email(name: name) }
8
+ title { "Individual-Title" }
9
+ twitter { "#{first_name}#{last_name}" }
10
+ www { Faker::Internet.url }
11
+ context { "Individual-Context" }
12
+ phone { "01 23 xx xx xx" }
13
+ fax { "09 xx xx xx xx" }
14
+ mobile { "06 xx xx xx xx" }
15
+ address { build(:dorsale_address) }
16
16
  end
17
17
  end
@@ -1,7 +1,7 @@
1
1
  FactoryBot.define do
2
2
  factory :expense_gun_category, class: ::Dorsale::ExpenseGun::Category do
3
- name { Faker::Lorem.word }
4
- code { Faker::Number.number(4) }
5
- vat_deductible { [true, false].sample }
3
+ name { Faker::Lorem.word }
4
+ code { Faker::Number.number(digits: 4) }
5
+ vat_deductible { [true, false].sample }
6
6
  end
7
7
  end
@@ -1,11 +1,11 @@
1
1
  FactoryBot.define do
2
2
  factory :expense_gun_expense_line, class: ::Dorsale::ExpenseGun::ExpenseLine do
3
- expense { build(:expense_gun_expense) }
4
- name { Faker::Lorem.sentence(3) }
5
- category { build(:expense_gun_category) }
6
- date { Faker::Date.backward(30) }
7
- total_all_taxes { rand(100..1000) }
8
- vat { rand(1..(total_all_taxes/5)) }
9
- company_part { [25, 50, 75, 100].sample }
3
+ expense { build(:expense_gun_expense) }
4
+ name { Faker::Lorem.sentence(word_count: 3) }
5
+ category { build(:expense_gun_category) }
6
+ date { Faker::Date.backward(days: 30) }
7
+ total_all_taxes { rand(100..1000) }
8
+ vat { rand(1..(total_all_taxes/5)) }
9
+ company_part { [25, 50, 75, 100].sample }
10
10
  end
11
11
  end
@@ -1,8 +1,8 @@
1
1
  FactoryBot.define do
2
2
  factory :expense_gun_expense, class: ::Dorsale::ExpenseGun::Expense do
3
- name { Faker::Lorem.sentence(3) }
4
- date { Date.current }
5
- user { create(:user) }
3
+ name { Faker::Lorem.sentence(word_count: 3) }
4
+ date { Date.current }
5
+ user { create(:user) }
6
6
 
7
7
  after(:create) { |expense|
8
8
  rand(2..5).times {
@@ -23,7 +23,7 @@ describe ::Dorsale::BillingMachine::InvoiceMultipleVatPdf, pdfs: true do
23
23
 
24
24
  let(:content) {
25
25
  generate!
26
- Yomu.new(invoice.pdf_file.path).text
26
+ PDF::Reader.new(invoice.pdf_file.path).pages.map(&:text).join("\n")
27
27
  }
28
28
 
29
29
  it "should not display global vat rate" do
@@ -23,7 +23,7 @@ describe ::Dorsale::BillingMachine::InvoiceSingleVatPdf, pdfs: true do
23
23
 
24
24
  let(:content) {
25
25
  generate!
26
- Yomu.new(invoice.pdf_file.path).text
26
+ PDF::Reader.new(invoice.pdf_file.path).pages.map(&:text).join("\n")
27
27
  }
28
28
 
29
29
  it "should display global vat rate" do
@@ -23,7 +23,7 @@ describe ::Dorsale::BillingMachine::QuotationMultipleVatPdf, pdfs: true do
23
23
 
24
24
  let(:content) {
25
25
  generate!
26
- Yomu.new(quotation.pdf_file.path).text
26
+ PDF::Reader.new(quotation.pdf_file.path).pages.map(&:text).join("\n")
27
27
  }
28
28
 
29
29
  it "should not display global vat rate" do
@@ -23,7 +23,7 @@ describe ::Dorsale::BillingMachine::QuotationSingleVatPdf, pdfs: true do
23
23
 
24
24
  let(:content) {
25
25
  generate!
26
- Yomu.new(quotation.pdf_file.path).text
26
+ PDF::Reader.new(quotation.pdf_file.path).pages.map(&:text).join("\n")
27
27
  }
28
28
 
29
29
  it "should display global vat rate" do
data/spec/rails_helper.rb CHANGED
@@ -4,7 +4,6 @@ require 'spec_helper'
4
4
  require File.expand_path("../dummy/config/environment", __FILE__)
5
5
  require 'rspec/rails'
6
6
  require "agilibox/rspec"
7
- require "yomu"
8
7
  # Add additional requires below this line. Rails is not loaded until this point!
9
8
  # Requires supporting ruby files with custom matchers and macros, etc,
10
9
  # in spec/support/ and its subdirectories.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dorsale
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.14.9
4
+ version: 3.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - agilidée
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-12 00:00:00.000000000 Z
11
+ date: 2021-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -50,20 +50,6 @@ dependencies:
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '99'
53
- - !ruby/object:Gem::Dependency
54
- name: virtus
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - "<"
58
- - !ruby/object:Gem::Version
59
- version: '99'
60
- type: :runtime
61
- prerelease: false
62
- version_requirements: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - "<"
65
- - !ruby/object:Gem::Version
66
- version: '99'
67
53
  - !ruby/object:Gem::Dependency
68
54
  name: slim-rails
69
55
  requirement: !ruby/object:Gem::Requirement
@@ -468,7 +454,6 @@ files:
468
454
  - app/assets/javascripts/dorsale/engines/billing_machine.coffee.erb
469
455
  - app/assets/javascripts/dorsale/engines/customer_vault.coffee
470
456
  - app/assets/javascripts/dorsale/engines/flyboy.coffee
471
- - app/assets/javascripts/url.min.js
472
457
  - app/assets/stylesheets/dorsale/all.sass
473
458
  - app/assets/stylesheets/dorsale/common.sass
474
459
  - app/assets/stylesheets/dorsale/common/comments.sass
@@ -550,14 +535,11 @@ files:
550
535
  - app/models/dorsale/customer_vault.rb
551
536
  - app/models/dorsale/customer_vault/activity_type.rb
552
537
  - app/models/dorsale/customer_vault/corporation.rb
553
- - app/models/dorsale/customer_vault/corporation_data.rb
554
538
  - app/models/dorsale/customer_vault/event.rb
555
539
  - app/models/dorsale/customer_vault/individual.rb
556
- - app/models/dorsale/customer_vault/individual_data.rb
557
540
  - app/models/dorsale/customer_vault/link.rb
558
541
  - app/models/dorsale/customer_vault/origin.rb
559
542
  - app/models/dorsale/customer_vault/person.rb
560
- - app/models/dorsale/customer_vault/person_data.rb
561
543
  - app/models/dorsale/email.rb
562
544
  - app/models/dorsale/expense_gun.rb
563
545
  - app/models/dorsale/expense_gun/category.rb
@@ -835,6 +817,8 @@ files:
835
817
  - db/migrate/20171023133219_customer_vault_events_add_contact_type.rb
836
818
  - db/migrate/20171024075514_customer_vault_contact_type_default_value.rb
837
819
  - db/migrate/20171115171425_dorsale_customer_vault_people_add_secondary_emails.rb
820
+ - db/migrate/20210202100529_billing_machine_add_positions.rb
821
+ - db/migrate/20210311131928_billing_machine_add_missing_unique_indexes.rb
838
822
  - features/access.feature
839
823
  - features/billing_machine_invoices.feature
840
824
  - features/billing_machine_multiple_vat.feature
@@ -989,7 +973,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
989
973
  - !ruby/object:Gem::Version
990
974
  version: '0'
991
975
  requirements: []
992
- rubygems_version: 3.0.3
976
+ rubygems_version: 3.1.4
993
977
  signing_key:
994
978
  specification_version: 4
995
979
  summary: Modular ERP made with Ruby on Rails
@@ -1 +0,0 @@
1
- /*! js-url - v2.3.0 - 2016-03-10 */window.url=function(){function a(){}function b(a){return decodeURIComponent(a.replace(/\+/g," "))}function c(a,b){var c=a.charAt(0),d=b.split(c);return c===a?d:(a=parseInt(a.substring(1),10),d[0>a?d.length+a:a-1])}function d(a,c){for(var d=a.charAt(0),e=c.split("&"),f=[],g={},h=[],i=a.substring(1),j=0,k=e.length;k>j;j++)if(f=e[j].match(/(.*?)=(.*)/),f||(f=[e[j],e[j],""]),""!==f[1].replace(/\s/g,"")){if(f[2]=b(f[2]||""),i===f[1])return f[2];h=f[1].match(/(.*)\[([0-9]+)\]/),h?(g[h[1]]=g[h[1]]||[],g[h[1]][h[2]]=f[2]):g[f[1]]=f[2]}return d===a?g:g[i]}return function(b,e){var f,g={};if("tld?"===b)return a();if(e=e||window.location.toString(),!b)return e;if(b=b.toString(),f=e.match(/^mailto:([^\/].+)/))g.protocol="mailto",g.email=f[1];else{if((f=e.match(/(.*?)\/#\!(.*)/))&&(e=f[1]+f[2]),(f=e.match(/(.*?)#(.*)/))&&(g.hash=f[2],e=f[1]),g.hash&&b.match(/^#/))return d(b,g.hash);if((f=e.match(/(.*?)\?(.*)/))&&(g.query=f[2],e=f[1]),g.query&&b.match(/^\?/))return d(b,g.query);if((f=e.match(/(.*?)\:?\/\/(.*)/))&&(g.protocol=f[1].toLowerCase(),e=f[2]),(f=e.match(/(.*?)(\/.*)/))&&(g.path=f[2],e=f[1]),g.path=(g.path||"").replace(/^([^\/])/,"/$1").replace(/\/$/,""),b.match(/^[\-0-9]+$/)&&(b=b.replace(/^([^\/])/,"/$1")),b.match(/^\//))return c(b,g.path.substring(1));if(f=c("/-1",g.path.substring(1)),f&&(f=f.match(/(.*?)\.(.*)/))&&(g.file=f[0],g.filename=f[1],g.fileext=f[2]),(f=e.match(/(.*)\:([0-9]+)$/))&&(g.port=f[2],e=f[1]),(f=e.match(/(.*?)@(.*)/))&&(g.auth=f[1],e=f[2]),g.auth&&(f=g.auth.match(/(.*)\:(.*)/),g.user=f?f[1]:g.auth,g.pass=f?f[2]:void 0),g.hostname=e.toLowerCase(),"."===b.charAt(0))return c(b,g.hostname);a()&&(f=g.hostname.match(a()),f&&(g.tld=f[3],g.domain=f[2]?f[2]+"."+f[3]:void 0,g.sub=f[1]||void 0)),g.port=g.port||("https"===g.protocol?"443":"80"),g.protocol=g.protocol||("443"===g.port?"https":"http")}return b in g?g[b]:"{}"===b?g:void 0}}(),"undefined"!=typeof jQuery&&jQuery.extend({url:function(a,b){return window.url(a,b)}});
@@ -1,10 +0,0 @@
1
- class Dorsale::CustomerVault::CorporationData < Dorsale::CustomerVault::PersonData
2
- attribute :legal_form, String
3
- attribute :immatriculation_number, String
4
- attribute :naf, String
5
- attribute :european_union_vat_number, String
6
- attribute :societe_com, String
7
- attribute :capital, Integer
8
- attribute :revenue, Integer
9
- attribute :number_of_employees, Integer
10
- end
@@ -1,3 +0,0 @@
1
- class Dorsale::CustomerVault::IndividualData < Dorsale::CustomerVault::PersonData
2
- attribute :title, String
3
- end
@@ -1,17 +0,0 @@
1
- require "virtus"
2
-
3
- class Dorsale::CustomerVault::PersonData
4
- include Virtus.model
5
-
6
- def self.dump(obj)
7
- JSON.dump(obj.attributes)
8
- end
9
-
10
- def self.load(json_string)
11
- new JSON.parse(json_string.presence || "{}")
12
- end
13
-
14
- def self.methods_to_delegate
15
- instance_methods - Dorsale::CustomerVault::PersonData.instance_methods
16
- end
17
- end