diff --git a/Gemfile b/Gemfile index d4f8c2d4..8f7f6bfc 100644 --- a/Gemfile +++ b/Gemfile @@ -78,7 +78,6 @@ gem 'foodsoft_wiki', path: 'plugins/wiki' # gem 'foodsoft_uservoice', path: 'plugins/uservoice' group :development do - gem 'letter_opener_web' gem 'listen' gem 'mailcatcher' gem 'sqlite3', '~> 1.3.6' diff --git a/Gemfile.lock b/Gemfile.lock index 733ae280..3d3fd01a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -176,8 +176,6 @@ GEM xpath (~> 3.2) case_transform (0.2) activesupport - childprocess (5.1.0) - logger (~> 1.5) chronic (0.10.2) coderay (1.1.3) coffee-rails (5.0.0) @@ -291,28 +289,16 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - launchy (3.1.1) - addressable (~> 2.8) - childprocess (~> 5.0) - logger (~> 1.6) less (2.6.0) commonjs (~> 0.2.7) less-rails (5.0.0) actionpack (>= 5.0) less (~> 2.6.0) sprockets (~> 3.0) - letter_opener (1.10.0) - launchy (>= 2.2, < 4) - letter_opener_web (2.0.0) - actionmailer (>= 5.2) - letter_opener (~> 1.7) - railties (>= 5.2) - rexml libv8 (3.16.14.19-x86_64-linux) listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - logger (1.7.0) loofah (2.21.3) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -661,7 +647,6 @@ DEPENDENCIES jquery-rails kaminari less-rails - letter_opener_web listen mailcatcher midi-smtp-server @@ -715,4 +700,4 @@ DEPENDENCIES whenever BUNDLED WITH - 2.4.22 + 2.4.21 diff --git a/app/assets/javascripts/order.js b/app/assets/javascripts/order.js index c7e49b20..baf0c5f4 100644 --- a/app/assets/javascripts/order.js +++ b/app/assets/javascripts/order.js @@ -90,20 +90,18 @@ $(document).off('change', '[class^="ajax-update-all-link-"] select').on('change' }); }); -$(document).off('change', '.ajax-update-sepa-select').on('change', '.ajax-update-sepa-select', function () { +$(document).off('change', '[class^="ajax-update-link-"] select').on('change', '[class^="ajax-update-link-"] select', function () { var selectedValue = $(this).val(); - var url = $(this).data('url'); - console.log(url); - console.log(selectedValue); + var url = $(this).closest('a').attr('href'); $.ajax({ url: url, method: 'PATCH', data: { sepa_sequence_type: selectedValue }, success: function (response) { - console.log("succeeded"); + // Handle success response }, error: function (error) { - console.error(error); + console.log(error); } }); }); @@ -134,7 +132,6 @@ $(document).on('ready turbolinks:load', function () { }); $(document).on('click', '.merge-orders-btn', function () { - const url = $(this).data('url'); const selectedOrderIds = $('input[name="order_ids_for_multi_order[]"]:checked').map(function () { return $(this).val(); diff --git a/app/controllers/concerns/send_group_order_invoice_pdf.rb b/app/controllers/concerns/send_group_order_invoice_pdf.rb index 76e71c99..0734ea2d 100644 --- a/app/controllers/concerns/send_group_order_invoice_pdf.rb +++ b/app/controllers/concerns/send_group_order_invoice_pdf.rb @@ -7,6 +7,14 @@ module Concerns::SendGroupOrderInvoicePdf invoice_data = group_order_invoice.load_data_for_invoice invoice_data[:title] = t('documents.group_order_invoice_pdf.title', supplier: invoice_data[:supplier]) invoice_data[:no_footer] = true + puts " + " + "____________" + " + " + "____________" + " + " + "____________" + " + " + "#{invoice_data.inspect}" + " + " + "____________"+ " + " + "____________"+ " + " + "____________" GroupOrderInvoicePdf.new invoice_data end diff --git a/app/controllers/finance/invoices_controller.rb b/app/controllers/finance/invoices_controller.rb index c85ae16b..d70b92ec 100644 --- a/app/controllers/finance/invoices_controller.rb +++ b/app/controllers/finance/invoices_controller.rb @@ -1,4 +1,4 @@ -class Finance::InvoicesController < OrderInvoiceControllerBase +class Finance::InvoicesController < ApplicationController before_action :authenticate_finance_or_invoices before_action :find_invoice, only: %i[show edit update destroy] diff --git a/app/controllers/group_order_invoices_controller.rb b/app/controllers/group_order_invoices_controller.rb index 4994515a..c72854b5 100644 --- a/app/controllers/group_order_invoices_controller.rb +++ b/app/controllers/group_order_invoices_controller.rb @@ -1,5 +1,6 @@ -class GroupOrderInvoicesController < OrderInvoicesControllerBase +class GroupOrderInvoicesController < ApplicationController include Concerns::SendGroupOrderInvoicePdf + before_action :authenticate_finance def show @group_order_invoice = GroupOrderInvoice.find(params[:id]) @@ -56,6 +57,21 @@ class GroupOrderInvoicesController < OrderInvoicesControllerBase end end + def select_sepa_sequence_type + @group_order_invoice = GroupOrderInvoice.find(params[:id]) + @group_order = @group_order_invoice.group_order + return unless params[:sepa_sequence_type] + + respond_to do |format| + @group_order_invoice.sepa_sequence_type = params[:sepa_sequence_type] + if @group_order_invoice.save! + format.js + else + format.json { render json: @group_order_invoice.errors, status: :unprocessable_entity } + end + end + end + def select_all_sepa_sequence_type @order = Order.find(params[:order_id]) @group_order_invoices = @order.group_orders.map(&:group_order_invoice).compact @@ -70,6 +86,31 @@ class GroupOrderInvoicesController < OrderInvoicesControllerBase end end + def toggle_paid + @group_order_invoice = GroupOrderInvoice.find(params[:id]) + respond_to do |format| + @group_order_invoice.paid = !@group_order_invoice.paid + if @group_order_invoice.save! + format.js + else + format.json { render json: @group_order_invoice.errors, status: :unprocessable_entity } + end + end + end + + def toggle_sepa_downloaded + @group_order_invoice = GroupOrderInvoice.find(params[:id]) + @order = @group_order_invoice.group_order.order + respond_to do |format| + @group_order_invoice.sepa_downloaded = !@group_order_invoice.sepa_downloaded + if @group_order_invoice.save! + format.js + else + format.json { render json: @group_order_invoice.errors, status: :unprocessable_entity } + end + end + end + def toggle_all_paid @order = Order.find(params[:order_id]) @group_order_invoices = @order.group_orders.map(&:group_order_invoice).compact @@ -123,14 +164,4 @@ class GroupOrderInvoicesController < OrderInvoicesControllerBase end end end - - protected - - def invoice_class - GroupOrderInvoice - end - - def set_related_group_order(invoice) - invoice.group_order - end end diff --git a/app/controllers/multi_orders_controller.rb b/app/controllers/multi_orders_controller.rb index 827aef21..f762a72c 100644 --- a/app/controllers/multi_orders_controller.rb +++ b/app/controllers/multi_orders_controller.rb @@ -39,18 +39,27 @@ class MultiOrdersController < ApplicationController end return end + begin @multi_order = MultiOrder.new @multi_order.orders = orders @multi_order.ends = orders.map(&:ends).max @multi_order.save! - suppliers = orders.map(&:supplier).map(&:name).join(', ') - msg = "Multi Bestellung für #{suppliers} erstellt" - respond_to do |format| - flash[:notice] = msg - format.js - format.html { redirect_to finance_order_index_path } + #create multi group orders + all_group_orders = orders.flat_map(&:group_orders) + + grouped_by_ordergroup = all_group_orders.group_by(&:ordergroup_id) + + grouped_by_ordergroup.each do |ordergroup_id, group_orders| + multi_group_order = MultiGroupOrder.create!( + multi_order: @multi_order, group_orders: group_orders + ) + # Now, associate each group_order with the new multi_group_order + group_orders.each do |group_order| + group_order.update!(multi_group_order: multi_group_order) + end end + redirect_to finance_order_index_path rescue ActiveRecord::RecordInvalid => e flash[:alert] = t('errors.general_msg', msg: e.message) respond_to do |format| @@ -62,13 +71,9 @@ class MultiOrdersController < ApplicationController def destroy @multi_order = MultiOrder.find(params[:id]) - if @multi_order.ordergroup_invoices.any? - flash[:alert]= "Lösche erst die Rechnungen" - redirect_to finance_order_index_path - else - @multi_order.destroy - redirect_to finance_order_index_path - + @multi_order.destroy + respond_to do |format| + format.html { redirect_to finance_order_index_path } end end @@ -118,7 +123,7 @@ class MultiOrdersController < ApplicationController format.xml do multi_group_orders.map(&:ordergroup_invoice).each(&:mark_sepa_downloaded) collective_debit = OrderCollectiveDirectDebitXml.new(multi_group_orders) - send_data collective_debit.xml_string, filename: @multi_order.name + '_Sammellastschrift' + '.xml', type: 'text/xml' + send_data collective_debit.xml_string, filename: @multi_order.orders.first.name + '_Sammellastschrift' + '.xml', type: 'text/xml' rescue SEPA::Error => e multi_group_orders.map(&:ordergroup_invoice).each(&:unmark_sepa_downloaded) render json: { error: e.message } diff --git a/app/controllers/order_invoices_controller_base.rb b/app/controllers/order_invoices_controller_base.rb deleted file mode 100644 index 77442945..00000000 --- a/app/controllers/order_invoices_controller_base.rb +++ /dev/null @@ -1,44 +0,0 @@ -class OrderInvoicesControllerBase < ApplicationController - before_action :authenticate_finance - - def select_sepa_sequence_type - @invoice = invoice_class.find(params[:id]) - return unless params[:sepa_sequence_type] - - @group_order = set_related_group_order(@invoice) - @multi_group_order = set_related_group_order(@invoice) - - @invoice.sepa_sequence_type = params[:sepa_sequence_type] - save_and_respond(@invoice) - end - - def toggle_paid - @invoice = invoice_class.find(params[:id]) - @invoice.paid = !@invoice.paid - save_and_respond(@invoice) - end - - def toggle_sepa_downloaded - @invoice = invoice_class.find(params[:id]) - @invoice.sepa_downloaded = !@invoice.sepa_downloaded - save_and_respond(@invoice) - end - - protected - - def save_and_respond(record) - if record.save! - respond_to { |format| format.js } - else - respond_to { |format| format.json { render json: record.errors, status: :unprocessable_entity } } - end - end - - def invoice_class - raise NotImplementedError - end - - def set_related_group_order(invoice) - raise NotImplementedError - end -end diff --git a/app/controllers/ordergroup_invoices_controller.rb b/app/controllers/ordergroup_invoices_controller.rb index 2d0525ea..edffe596 100644 --- a/app/controllers/ordergroup_invoices_controller.rb +++ b/app/controllers/ordergroup_invoices_controller.rb @@ -1,12 +1,15 @@ -class OrdergroupInvoicesController < OrderInvoicesControllerBase +class OrdergroupInvoicesController < ApplicationController include Concerns::SendGroupOrderInvoicePdf + before_action :authenticate_finance + # download create and new ordergroupinvoice + # has multiple group orders and one ordergroup - # def new - # @ordergroup_invoice = OrdergroupInvoice.new - # @ordergroup_invoice.payment_method = FoodsoftConfig[:ordergroup_invoices][:payment_method] || I18n.t('activerecord.attributes.ordergroup_invoice.payment_method') - # @ordergroup_invoice.sepa_sequence_type = params[:sepa_sequence_type] - # end + def new + @ordergroup_invoice = OrdergroupInvoice.new + @ordergroup_invoice.payment_method = FoodsoftConfig[:ordergroup_invoices][:payment_method] || I18n.t('activerecord.attributes.ordergroup_invoice.payment_method') + @ordergroup_invoice.sepa_sequence_type = params[:sepa_sequence_type] + end def show @ordergroup_invoice = OrdergroupInvoice.find(params[:id]) @@ -64,15 +67,18 @@ class OrdergroupInvoicesController < OrderInvoicesControllerBase end end - def send_all - @multi_order = MultiOrder.find(params[:multi_order_id]) - @ordergroup_invoices = @multi_order.multi_group_orders.map(&:ordergroup_invoice).compact - @ordergroup_invoices.each do |oi| - oi.send_invoice - end + + def select_sepa_sequence_type + @ordergroup_invoice = OrdergroupInvoice.find(params[:id]) + @multi_group_order = @ordergroup_invoice.multi_group_order + return unless params[:sepa_sequence_type] + respond_to do |format| - format.html do - redirect_to finance_order_index_path, notice: I18n.t('ordergroup_invoices.send_all.success') + @ordergroup_invoice.sepa_sequence_type = params[:sepa_sequence_type] + if @ordergroup_invoice.save! + format.js + else + format.json { render json: @ordergroup_invoice.errors, status: :unprocessable_entity } end end end @@ -91,6 +97,31 @@ class OrdergroupInvoicesController < OrderInvoicesControllerBase end end + def toggle_paid + @ordergroup_invoice = OrdergroupInvoice.find(params[:id]) + respond_to do |format| + @ordergroup_invoice.paid = !@ordergroup_invoice.paid + if @ordergroup_invoice.save! + format.js + else + format.json { render json: @ordergroup_invoice.errors, status: :unprocessable_entity } + end + end + end + + def toggle_sepa_downloaded + @ordergroup_invoice = OrdergroupInvoice.find(params[:id]) + @multi_order= @ordergroup_invoice.multi_group_order.multi_order + respond_to do |format| + @ordergroup_invoice.sepa_downloaded = !@ordergroup_invoice.sepa_downloaded + if @ordergroup_invoice.save! + format.js + else + format.json { render json: @ordergroup_invoice.errors, status: :unprocessable_entity } + end + end + end + def toggle_all_paid @multi_order= MultiOrder.find(params[:multi_order_id]) @ordergroup_invoices = @multi_order.multi_group_orders.map(&:ordergroup_invoice).compact @@ -144,12 +175,5 @@ class OrdergroupInvoicesController < OrderInvoicesControllerBase end end end - protected - def invoice_class - OrdergroupInvoice - end - def set_related_group_order(invoice) - invoice.multi_group_order - end end diff --git a/app/documents/group_order_invoice_pdf.rb b/app/documents/group_order_invoice_pdf.rb index 1bf4741b..52ea0b38 100644 --- a/app/documents/group_order_invoice_pdf.rb +++ b/app/documents/group_order_invoice_pdf.rb @@ -81,22 +81,12 @@ class GroupOrderInvoicePdf < RenderPdf data = [I18n.t('documents.group_order_invoice_pdf.vat_exempt_rows')] move_down 10 # no sinle group_order_id, capice? get all the articles. - - group_order_articles = GroupOrderArticle.where(group_order_id: @options[:group_order_ids]) + group_order_articles = GroupOrderArticle.where(group_order_ids: @options.group_order_ids) separate_deposits = FoodsoftConfig[:group_order_invoices]&.[](:separate_deposits) - supplier = "" - headlines = [] - index = 0 group_order_articles.each do |goa| # if no unit is received, nothing is to be charged next if goa.result.to_i == 0 - index +=1 - if goa.group_order.order.supplier.name != supplier - headlines << index - supplier = goa.group_order.order.supplier.name - data << [supplier,"","",""] - index +=1 - end + goa_total_price = separate_deposits ? goa.total_price_without_deposit : goa.total_price data << [goa.order_article.article.name, goa.result.to_i, @@ -118,9 +108,9 @@ class GroupOrderInvoicePdf < RenderPdf table.position = :center table.cells.border_width = 1 table.cells.border_color = '666666' + table.row(0).column(0..4).width = 80 table.row(0).column(0).width = 180 - table.row(headlines).font_style= :bold table.row(0).border_bottom_width = 2 table.columns(1).align = :right table.columns(1..6).align = :right @@ -182,21 +172,13 @@ class GroupOrderInvoicePdf < RenderPdf else [I18n.t('documents.group_order_invoice_pdf.price_markup_rows', marge: marge)] end - - group_order_articles = GroupOrderArticle.where(group_order_id: @options[:group_order_ids]).includes(group_order: { order: :supplier }) - index = 0 - supplier_headlines = [] - group_order_articles.group_by { |goa| goa.group_order.order.supplier.name }.each do |supplier_name, articles| - data << [supplier_name, "", "", "", "", ""] - index += 1 - supplier_headlines << index - - articles.each do |goa| + goa_tax_hash = GroupOrderArticle.where(group_order_id: @options[:group_order_ids]).find_each.group_by { |oat| oat.order_article.price.tax } + goa_tax_hash.each do |tax, group_order_articles| + group_order_articles.each do |goa| + # if no unit is received, nothing is to be charged next if goa.result.to_i == 0 - index += 1 order_article = goa.order_article - tax = order_article.price.tax goa_total_net = goa.result * order_article.price.price goa_total_fc = separate_deposits ? goa.total_price_without_deposit : goa.total_price @@ -254,9 +236,6 @@ class GroupOrderInvoicePdf < RenderPdf table.row(0).border_bottom_width = 2 table.columns(1).align = :right table.columns(1..6).align = :right - supplier_headlines.each do |row_index| - table.row(row_index).columns(0..6).style(font_style: :bold) - end end if marge > 0 diff --git a/app/helpers/invoice_helper.rb b/app/helpers/invoice_helper.rb index 41ff2d36..36d511cc 100644 --- a/app/helpers/invoice_helper.rb +++ b/app/helpers/invoice_helper.rb @@ -1,12 +1,4 @@ module InvoiceHelper - - SEPA_SEQUENCE_TYPES = { - FRST: "Erst-Lastschrift", - RCUR: "Folge-Lastschrift", - OOFF: "Einmalige Lastschrift", - FNAL: "Letztmalige Lastschrift" - }.freeze - def generate_invoice_number(instance, count) trailing_number = count.to_s.rjust(4, '0') if GroupOrderInvoice.find_by(invoice_number: instance.invoice_date.strftime("%Y%m%d") + trailing_number) || OrdergroupInvoice.find_by(invoice_number: instance.invoice_date.strftime("%Y%m%d") + trailing_number) diff --git a/app/jobs/notify_ordergroup_invoice_job.rb b/app/jobs/notify_ordergroup_invoice_job.rb deleted file mode 100644 index b218745b..00000000 --- a/app/jobs/notify_ordergroup_invoice_job.rb +++ /dev/null @@ -1,12 +0,0 @@ -class NotifyOrdergroupInvoiceJob < ApplicationJob - def perform(ordergroup_invoice) - ordergroup = ordergroup_invoice.multi_group_order.ordergroup - ordergroup.users.each do |user| - ordergroup_invoice.update!(email_sent_at: Time.current) - Mailer.deliver_now_with_user_locale user do - Mailer.ordergroup_invoice(ordergroup_invoice, user) - end - end - end - end - \ No newline at end of file diff --git a/app/mailers/mailer.rb b/app/mailers/mailer.rb index 152c8b28..2b06ce8e 100644 --- a/app/mailers/mailer.rb +++ b/app/mailers/mailer.rb @@ -63,18 +63,6 @@ class Mailer < ActionMailer::Base subject: I18n.t('mailer.group_order_invoice.subject', group: @group.name, supplier: @supplier) end - def ordergroup_invoice(ordergroup_invoice, user) - @user = user - @ordergroup_invoice = ordergroup_invoice - @multi_group_order = ordergroup_invoice.multi_group_order - @multi_order = @multi_group_order.multi_order - @supplier = @multi_order.orders.map(&:supplier).map(&:name).uniq.join(', ') - @group = @multi_group_order.ordergroup - add_ordergroup_invoice_attachments(ordergroup_invoice) - mail to: user, - subject: I18n.t('mailer.ordergroup_invoice.subject', group: @group.name, supplier: @supplier) - end - # Sends order result for specific Ordergroup def order_result(user, group_order) @order = group_order.order @@ -198,10 +186,6 @@ class Mailer < ActionMailer::Base attachments[attachment_name] = GroupOrderInvoicePdf.new(group_order_invoice.load_data_for_invoice).to_pdf end - def add_ordergroup_invoice_attachments(ordergroup_invoice) - add_group_order_invoice_attachments(ordergroup_invoice) - end - # separate method to allow plugins to mess with the text def additonal_welcome_text(user); end diff --git a/app/models/concerns/invoice_common.rb b/app/models/concerns/invoice_common.rb deleted file mode 100644 index 7f9b8d87..00000000 --- a/app/models/concerns/invoice_common.rb +++ /dev/null @@ -1,34 +0,0 @@ -# app/models/concerns/invoice_common.rb -module InvoiceCommon - extend ActiveSupport::Concern - - included do - include InvoiceHelper - - validates_presence_of :invoice_number - validates_uniqueness_of :invoice_number - validate :tax_number_set - - after_initialize :init, unless: :persisted? - end - - def mark_sepa_downloaded - self.sepa_downloaded = true - save - end - - def unmark_sepa_downloaded - self.sepa_downloaded = false - save - end - - def name - I18n.t("activerecord.attributes.#{self.class.name.underscore}.name") + "_#{invoice_number}" - end - - def tax_number_set - return if FoodsoftConfig[:contact][:tax_number].present? - errors.add(:base, "Keine Steuernummer in FoodsoftConfig :contact gesetzt") - end - end - \ No newline at end of file diff --git a/app/models/group_order.rb b/app/models/group_order.rb index 6dbc8d09..2045ac12 100644 --- a/app/models/group_order.rb +++ b/app/models/group_order.rb @@ -11,7 +11,7 @@ class GroupOrder < ApplicationRecord has_one :financial_transaction has_one :group_order_invoice belongs_to :ordergroup_invoice, optional: true - belongs_to :multi_group_order, optional: true + belongs_to :multi_group_order, optional: true, dependent: :destroy belongs_to :multi_order, optional: true belongs_to :updated_by, optional: true, class_name: 'User', foreign_key: 'updated_by_user_id' diff --git a/app/models/group_order_invoice.rb b/app/models/group_order_invoice.rb index 310e082b..8fcb65f9 100644 --- a/app/models/group_order_invoice.rb +++ b/app/models/group_order_invoice.rb @@ -1,9 +1,34 @@ class GroupOrderInvoice < ApplicationRecord - include InvoiceCommon + include InvoiceHelper belongs_to :group_order validates_presence_of :group_order - validates_uniqueness_of :group_order_id + validates_uniqueness_of :invoice_number + validate :tax_number_set + after_initialize :init, unless: :persisted? + + enum sequence_type: { + FRST: "Erst-Lastschrift", + RCUR: "Folge-Lastschrift", + OOFF: "Einmalige Lastschrift", + FNAL: "Letztmalige Lastschrift" + } + + def tax_number_set + return unless FoodsoftConfig[:contact][:tax_number].blank? + + errors.add(:group_order_invoice, "Keine Steuernummer in FoodsoftConfig :contact gesetzt") + end + + def mark_sepa_downloaded + self.sepa_downloaded = true + self.save + end + + def unmark_sepa_downloaded + self.sepa_downloaded = false + self.save + end def init self.invoice_date = Time.now unless invoice_date @@ -11,6 +36,10 @@ class GroupOrderInvoice < ApplicationRecord self.payment_method = group_order&.financial_transaction&.financial_transaction_type&.name || FoodsoftConfig[:group_order_invoices]&.[](:payment_method) || I18n.t('activerecord.attributes.group_order_invoice.payment_method') unless self.payment_method end + def name + I18n.t('activerecord.attributes.group_order_invoice.name') + "_#{invoice_number}" + end + def load_data_for_invoice invoice_data = {} order = group_order.order diff --git a/app/models/multi_group_order.rb b/app/models/multi_group_order.rb index 7a66afb0..9cb89aad 100644 --- a/app/models/multi_group_order.rb +++ b/app/models/multi_group_order.rb @@ -1,10 +1,8 @@ class MultiGroupOrder < ApplicationRecord - belongs_to :multi_order, optional: false - has_many :group_orders, dependent: :nullify + belongs_to :multi_order + has_many :group_orders has_one :ordergroup_invoice, dependent: :destroy - validates :multi_order, presence: true - def ordergroup group_orders.first&.ordergroup end diff --git a/app/models/multi_order.rb b/app/models/multi_order.rb index 78253bde..c6ab683f 100644 --- a/app/models/multi_order.rb +++ b/app/models/multi_order.rb @@ -6,10 +6,11 @@ class MultiOrder < ApplicationRecord #TODO: diese association lösen has_many :group_orders, through: :multi_group_orders # has_many :ordergroups, through: :group_orders - has_many :ordergroup_invoices, through: :multi_group_orders + has_many :ordergroup_invoices, through: :group_orders - validate :check_orders - after_create :create_multi_group_orders + #make sure order has no multi_order_id + #make sure orders are not in a multi_order + before_create :check_orders def name orders.map(&:name).join(', ') @@ -39,38 +40,15 @@ class MultiOrder < ApplicationRecord end private - def check_orders - unless orders.present? - errors.add(:base, "No orders selected") - return - end orders.each do |order| - if order.group_orders.blank? - errors.add(:base, "Order #{order.name} has no group orders") - end - unless order.closed? - errors.add(:base, "Order #{order.name} is not closed") - end - if order.group_orders.any? { |go| go.group_order_invoice.present? } - errors.add(:base, "Order #{order.name} has group order invoices") - end + errors.add(:base, "Order #{order.name} is already in a multi order") unless order.multi_order_id.nil? + #closed==abgerechnet + errors.add(:base, "Order #{order.name} not closed") unless order.closed? end - end - - def create_multi_group_orders - return if orders.empty? - all_group_orders = orders.flat_map(&:group_orders) - grouped_by_ordergroup = all_group_orders.group_by(&:ordergroup_id) - - grouped_by_ordergroup.each do |ordergroup_id, group_orders| - multi_group_order = MultiGroupOrder.create!( - multi_order: self, group_orders: group_orders - ) - # Now, associate each group_order with the new multi_group_order - group_orders.each do |group_order| - group_order.update!(multi_group_order: multi_group_order) - end + if errors.any? + errors.add(:base, "Cannot create multi order with unfinished orders") + raise ActiveRecord::Rollback end end end diff --git a/app/models/ordergroup_invoice.rb b/app/models/ordergroup_invoice.rb index 1b1e4414..02eda363 100644 --- a/app/models/ordergroup_invoice.rb +++ b/app/models/ordergroup_invoice.rb @@ -1,10 +1,25 @@ class OrdergroupInvoice < ApplicationRecord - include InvoiceCommon + include InvoiceHelper - belongs_to :multi_group_order + belongs_to :multi_group_order, optional: true + # has_many :group_orders, through: :multi_group_order, dependent: :nullify + + validates_presence_of :invoice_number + validates_uniqueness_of :invoice_number + validate :tax_number_set after_initialize :init, unless: :persisted? + # accepts_nested_attributes_for :group_orders, :multi_group_order + + + enum sequence_type: { + FRST: "Erst-Lastschrift", + RCUR: "Folge-Lastschrift", + OOFF: "Einmalige Lastschrift", + FNAL: "Letztmalige Lastschrift" + } + def init self.invoice_date = Time.now unless invoice_date self.invoice_number = generate_invoice_number(self, 1) unless self.invoice_number @@ -17,8 +32,24 @@ class OrdergroupInvoice < ApplicationRecord group_orders.first.ordergroup end - def send_invoice - NotifyOrdergroupInvoiceJob.perform_now(self) + def tax_number_set + return if FoodsoftConfig[:contact][:tax_number].present? + + errors.add(:cumulative_invoice, "Keine Steuernummer in FoodsoftConfig :contact gesetzt") + end + + def mark_sepa_downloaded + self.sepa_downloaded = true + self.save + end + + def unmark_sepa_downloaded + self.sepa_downloaded = false + self.save + end + + def name + I18n.t('activerecord.attributes.ordergroup_invoice.name') + "_#{invoice_number}" end def load_data_for_invoice diff --git a/app/views/group_order_invoices/_links.html.haml b/app/views/group_order_invoices/_links.html.haml index a8e3d227..bb091bb0 100644 --- a/app/views/group_order_invoices/_links.html.haml +++ b/app/views/group_order_invoices/_links.html.haml @@ -19,7 +19,6 @@ %th=I18n.t('activerecord.attributes.group_order_invoice.links.sepa_downloaded') %th=I18n.t('activerecord.attributes.group_order_invoice.links.sepa_sequence_type') %th=I18n.t('activerecord.attributes.group_order_invoice.links.sepa_select') - %th= "Rechnungsnummer" %th %tbody - order.group_orders.includes([:group_order_invoice, :ordergroup]).each do |go| @@ -53,7 +52,6 @@ %td %td %td - %td - if order.group_orders.map(&:group_order_invoice).compact.present? %tr.order-row @@ -70,6 +68,5 @@ %td .div{id: "select_all_sepa_#{order.id}"} = render :partial => 'group_order_invoices/collective_direct_debit', locals: { order: order } - %td %td = link_to I18n.t('activerecord.attributes.group_order_invoice.links.download_all_zip'), download_all_group_order_invoices_path(order), class: 'btn btn-block' diff --git a/app/views/group_order_invoices/_select_all_sepa_sequence_type.html.haml b/app/views/group_order_invoices/_select_all_sepa_sequence_type.html.haml index a7b3deca..9caffeb1 100644 --- a/app/views/group_order_invoices/_select_all_sepa_sequence_type.html.haml +++ b/app/views/group_order_invoices/_select_all_sepa_sequence_type.html.haml @@ -1,2 +1,2 @@ = link_to select_all_sepa_sequence_type_group_order_invoices_path(order_id: order.id), remote: true, method: :patch, class: "ajax-update-all-link-#{order.id}" , data: { turbolinks: false } do - = select_tag 'sepa_sequence_type', options_for_select(InvoiceHelper::SEPA_SEQUENCE_TYPES.keys.map { |st| [I18n.t("activerecord.attributes.group_order_invoice.sequence_type.#{st}"), st] }, selected: @sequence_type || order.group_orders.map(&:group_order_invoice)&.compact&.first.sepa_sequence_type), class: 'form-control', id: "all_sepa_sequence_type_#{order.id}" \ No newline at end of file + = select_tag 'sepa_sequence_type', options_for_select(GroupOrderInvoice.sequence_types.keys.map { |st| [I18n.t("activerecord.attributes.group_order_invoice.sequence_type.#{st}"), st] }, selected: @sequence_type || order.group_orders.map(&:group_order_invoice)&.compact&.first.sepa_sequence_type), class: 'form-control', id: "all_sepa_sequence_type_#{order.id}" \ No newline at end of file diff --git a/app/views/group_order_invoices/_select_sepa_sequence_type.html.haml b/app/views/group_order_invoices/_select_sepa_sequence_type.html.haml index c4121b5e..1c930df1 100644 --- a/app/views/group_order_invoices/_select_sepa_sequence_type.html.haml +++ b/app/views/group_order_invoices/_select_sepa_sequence_type.html.haml @@ -1 +1,2 @@ -= select_tag :sepa_sequence_type, options_for_select(InvoiceHelper::SEPA_SEQUENCE_TYPES.map { |k, v| [v, k] }, group_order_invoice.sepa_sequence_type), class: 'form-control ajax-update-sepa-select', id: "sepa_sequence_type_multi_#{group_order.id}", data: { url: select_sepa_sequence_type_group_order_invoice_path(group_order_invoice) } \ No newline at end of file += link_to select_sepa_sequence_type_group_order_invoice_path(group_order_invoice), remote: true, method: :patch, class: "ajax-update-link-#{group_order.id}", data: { turbolinks: false } do + = select_tag 'sepa_sequence_type', options_for_select(GroupOrderInvoice.sequence_types.keys.map { |st| [I18n.t("activerecord.attributes.group_order_invoice.sequence_type.#{st}"), st] }, selected: group_order_invoice.sepa_sequence_type ), class: 'form-control', id: "sepa_sequence_type_#{group_order.id}" \ No newline at end of file diff --git a/app/views/group_order_invoices/select_sepa_sequence_type.js.erb b/app/views/group_order_invoices/select_sepa_sequence_type.js.erb index d92ef8ed..96bf519f 100644 --- a/app/views/group_order_invoices/select_sepa_sequence_type.js.erb +++ b/app/views/group_order_invoices/select_sepa_sequence_type.js.erb @@ -1 +1 @@ -$("#select_sepa_sequence_type_<%= @invoice.id %>").html("<%= j(render partial: 'select_sepa_sequence_type', locals: {group_order_invoice: @invoice, group_order: @group_order}) %>"); +$("#select_sepa_sequence_type_<%= @group_order_invoice.id %>").html("<%= j(render partial: 'select_sepa_sequence_type', locals: {group_order_invoice: @group_order_invoice, group_order: @group_order}) %>"); \ No newline at end of file diff --git a/app/views/mailer/ordergroup_invoice.text.haml b/app/views/mailer/ordergroup_invoice.text.haml deleted file mode 100644 index 75948fbe..00000000 --- a/app/views/mailer/ordergroup_invoice.text.haml +++ /dev/null @@ -1 +0,0 @@ -= raw t '.text', group: @group.name, supplier: @supplier , foodcoop: FoodsoftConfig[:name] diff --git a/app/views/ordergroup_invoices/_links.html.haml b/app/views/ordergroup_invoices/_links.html.haml index fc72f10d..5153b362 100644 --- a/app/views/ordergroup_invoices/_links.html.haml +++ b/app/views/ordergroup_invoices/_links.html.haml @@ -25,29 +25,26 @@ %tbody - multi_order.multi_group_orders.each do |mgo| -if mgo.ordergroup_invoice.present? - %tr.order-row{id: "multi_group_order_#{mgo.id}"} - %td - = link_to mgo.ordergroup&.name, edit_admin_ordergroup_path(mgo.ordergroup) - %td - .div{id: "paid_multi_#{mgo.ordergroup_invoice.id}"} - = render :partial => "ordergroup_invoices/toggle_paid", locals: { ordergroup_invoice: mgo.ordergroup_invoice } - %td - .div{id: "sepa_downloaded_multi_#{mgo.ordergroup_invoice.id}"} - = render :partial => "ordergroup_invoices/toggle_sepa_downloaded", locals: { ordergroup_invoice: mgo.ordergroup_invoice } - %td - .div{id: "select_sepa_sequence_type_multi_#{mgo.ordergroup_invoice.id}"} - =render :partial => 'ordergroup_invoices/select_sepa_sequence_type', locals:{ ordergroup_invoice: mgo.ordergroup_invoice, multi_group_order: mgo } - %td - = check_box_tag "group_order_ids_for_multi_order_#{multi_order.id}", mgo.id, false, class: "group-order-checkbox", id: "group_order_#{mgo.id}_included_in_sepa", data: { multi_group_order_id: mgo.id } - %td - %b= mgo.ordergroup_invoice.invoice_number - - if mgo.ordergroup_invoice.email_sent_at.present? - %br/ - = I18n.t('activerecord.attributes.ordergroup_invoice.email_sent') - = mgo.ordergroup_invoice.email_sent_at.strftime("%d.%m.%Y %H:%M") - %td - = link_to I18n.t('activerecord.attributes.group_order_invoice.links.delete'), mgo.ordergroup_invoice, method: :delete, class: 'btn btn-block btn-danger', remote: true, data: { confirm: I18n.t('ui.confirm_delete', name: "Bestellgruppenrechnung für #{mgo.ordergroup.name}" ) } - = link_to I18n.t('activerecord.attributes.group_order_invoice.links.download'), ordergroup_invoice_path(mgo.ordergroup_invoice, :format => 'pdf'), class: 'btn btn-block' + - if mgo.ordergroup_invoice + %tr.order-row{id: "multi_group_order_#{mgo.id}"} + %td + = link_to mgo.ordergroup&.name, edit_admin_ordergroup_path(mgo.ordergroup) + %td + .div{id: "paid_multi_#{mgo.ordergroup_invoice.id}"} + = render :partial => "ordergroup_invoices/toggle_paid", locals: { ordergroup_invoice: mgo.ordergroup_invoice } + %td + .div{id: "sepa_downloaded_multi_#{mgo.ordergroup_invoice.id}"} + = render :partial => "ordergroup_invoices/toggle_sepa_downloaded", locals: { ordergroup_invoice: mgo.ordergroup_invoice } + %td + .div{id: "select_sepa_sequence_type_multi_#{mgo.ordergroup_invoice.id}"} + =render :partial => 'ordergroup_invoices/select_sepa_sequence_type', locals:{ ordergroup_invoice: mgo.ordergroup_invoice, multi_group_order: mgo } + %td + = check_box_tag "group_order_ids_for_multi_order_#{multi_order.id}", mgo.id, false, class: "group-order-checkbox", id: "group_order_#{mgo.id}_included_in_sepa", data: { multi_group_order_id: mgo.id } + %td + %b= mgo.ordergroup_invoice.invoice_number + %td + = link_to I18n.t('activerecord.attributes.group_order_invoice.links.delete'), mgo.ordergroup_invoice, method: :delete, class: 'btn btn-block btn-danger', remote: true, data: { confirm: I18n.t('ui.confirm_delete', name: "Bestellgruppenrechnung für #{mgo.ordergroup.name}" ) } + = link_to I18n.t('activerecord.attributes.group_order_invoice.links.download'), ordergroup_invoice_path(mgo.ordergroup_invoice, :format => 'pdf'), class: 'btn btn-block' - else %tr %td @@ -74,8 +71,4 @@ .div{id: "select_all_sepa_#{multi_order.id}"} = render :partial => 'ordergroup_invoices/collective_direct_debit', locals: { multi_order: multi_order } %td - %td - - if multi_order.multi_group_orders.count == multi_order.multi_group_orders.map(&:ordergroup_invoice).compact&.count - = link_to I18n.t('activerecord.attributes.group_order_invoice.links.download_all_zip'), download_all_ordergroup_invoices_path(multi_order), class: 'btn btn-block' - -# sends all ordergroup invoices to the ordergoups mail address via notifyjob - = link_to I18n.t('activerecord.attributes.group_order_invoice.links.send_all_by_email'), send_all_ordergroup_invoices_path(multi_order), class: 'btn btn-block', method: :post, data: { confirm: I18n.t('activerecord.attributes.group_order_invoice.links.confirm_send_all', ordergroups: "#{multi_order.multi_group_orders.map(&:ordergroup).map(&:name).join(', ')}" ) } + = link_to I18n.t('activerecord.attributes.group_order_invoice.links.download_all_zip'), download_all_ordergroup_invoices_path(multi_order), class: 'btn btn-block' diff --git a/app/views/ordergroup_invoices/_select_all_sepa_sequence_type.html.haml b/app/views/ordergroup_invoices/_select_all_sepa_sequence_type.html.haml index 01c26923..a4dc9580 100644 --- a/app/views/ordergroup_invoices/_select_all_sepa_sequence_type.html.haml +++ b/app/views/ordergroup_invoices/_select_all_sepa_sequence_type.html.haml @@ -1,2 +1,2 @@ = link_to select_all_sepa_sequence_type_ordergroup_invoices_path(multi_order_id: multi_order.id), remote: true, method: :patch, class: "ajax-update-all-link-#{multi_order.id}" , data: { turbolinks: false } do - = select_tag 'sepa_sequence_type', options_for_select(InvoiceHelper::SEPA_SEQUENCE_TYPES.keys.map { |st| [I18n.t("activerecord.attributes.group_order_invoice.sequence_type.#{st}"), st] }, selected: @sequence_type || multi_order.multi_group_orders.map(&:ordergroup_invoice)&.compact&.first&.sepa_sequence_type), class: 'form-control', id: "all_sepa_sequence_type_multi_#{multi_order.id}" \ No newline at end of file + = select_tag 'sepa_sequence_type', options_for_select(OrdergroupInvoice.sequence_types.keys.map { |st| [I18n.t("activerecord.attributes.group_order_invoice.sequence_type.#{st}"), st] }, selected: @sequence_type || multi_order.multi_group_orders.map(&:ordergroup_invoice)&.compact&.first&.sepa_sequence_type), class: 'form-control', id: "all_sepa_sequence_type_multi_#{multi_order.id}" \ No newline at end of file diff --git a/app/views/ordergroup_invoices/_select_sepa_sequence_type.html.haml b/app/views/ordergroup_invoices/_select_sepa_sequence_type.html.haml index 8b92abfd..61799883 100644 --- a/app/views/ordergroup_invoices/_select_sepa_sequence_type.html.haml +++ b/app/views/ordergroup_invoices/_select_sepa_sequence_type.html.haml @@ -1 +1,2 @@ -= select_tag :sepa_sequence_type, options_for_select(InvoiceHelper::SEPA_SEQUENCE_TYPES.map { |k, v| [v, k] }, ordergroup_invoice.sepa_sequence_type), class: 'form-control ajax-update-sepa-select', id: "sepa_sequence_type_multi_#{multi_group_order.id}", data: { url: select_sepa_sequence_type_ordergroup_invoice_path(ordergroup_invoice) } \ No newline at end of file += link_to select_sepa_sequence_type_ordergroup_invoice_path(ordergroup_invoice), remote: true, method: :patch, class: "ajax-update-link-#{multi_group_order.id}", data: { turbolinks: false } do + = select_tag 'sepa_sequence_type', options_for_select(OrdergroupInvoice.sequence_types.keys.map { |st| [I18n.t("activerecord.attributes.group_order_invoice.sequence_type.#{st}"), st] }, selected: ordergroup_invoice.sepa_sequence_type ), class: 'form-control', id: "sepa_sequence_type_multi_#{multi_group_order.id}" \ No newline at end of file diff --git a/app/views/ordergroup_invoices/_toggle_sepa_downloaded.html.haml b/app/views/ordergroup_invoices/_toggle_sepa_downloaded.html.haml index 064d1838..f4bfcbd1 100644 --- a/app/views/ordergroup_invoices/_toggle_sepa_downloaded.html.haml +++ b/app/views/ordergroup_invoices/_toggle_sepa_downloaded.html.haml @@ -1,2 +1,2 @@ = link_to toggle_sepa_downloaded_ordergroup_invoice_path(ordergroup_invoice), remote: true, method: :patch do - = check_box_tag 'sepa_downloaded', '1', ordergroup_invoice.sepa_downloaded , class: 'form-check-input', id: "sepa_downloaded_multi_#{ordergroup_invoice.id}" \ No newline at end of file + = check_box_tag 'sepa_downloaded', '1', ordergroup_invoice.sepa_downloaded , class: 'form-check-input', id: "sepa_downloaded_multii_#{ordergroup_invoice.id}" \ No newline at end of file diff --git a/app/views/ordergroup_invoices/select_sepa_sequence_type.js.erb b/app/views/ordergroup_invoices/select_sepa_sequence_type.js.erb index b8fe4813..fa249c87 100644 --- a/app/views/ordergroup_invoices/select_sepa_sequence_type.js.erb +++ b/app/views/ordergroup_invoices/select_sepa_sequence_type.js.erb @@ -1 +1 @@ -$("#select_sepa_sequence_type_multi_<%= @invoice.id %>").html("<%= j(render partial: 'select_sepa_sequence_type', locals: {ordergroup_invoice: @invoice, multi_group_order: @group_order}) %>"); +$("#select_sepa_sequence_type_multi_<%= @ordergroup_invoice.id %>").html("<%= j(render partial: 'select_sepa_sequence_type', locals: {ordergroup_invoice: @ordergroup_invoice, multi_group_order: @multi_group_order}) %>"); \ No newline at end of file diff --git a/app/views/ordergroup_invoices/toggle_paid.js.erb b/app/views/ordergroup_invoices/toggle_paid.js.erb index 0832d8bf..4097f4d6 100644 --- a/app/views/ordergroup_invoices/toggle_paid.js.erb +++ b/app/views/ordergroup_invoices/toggle_paid.js.erb @@ -1 +1 @@ -$("#paid_multi_<%= @invoice.id %>").html("<%= escape_javascript(render partial: 'toggle_paid', locals: {ordergroup_invoice: @invoice}) %>"); +$("#paid_multi_<%= @ordergroup_invoice.id %>").html("<%= escape_javascript(render partial: 'toggle_paid', locals: {ordergroup_invoice: @ordergroup_invoice}) %>"); diff --git a/app/views/ordergroup_invoices/toggle_sepa_downloaded.js.erb b/app/views/ordergroup_invoices/toggle_sepa_downloaded.js.erb index ffe34b60..9a57c052 100644 --- a/app/views/ordergroup_invoices/toggle_sepa_downloaded.js.erb +++ b/app/views/ordergroup_invoices/toggle_sepa_downloaded.js.erb @@ -1 +1 @@ -$("#sepa_downloaded_multi_<%= @invoice.id %>").html("<%= escape_javascript(render partial: 'toggle_sepa_downloaded', locals: {ordergroup_invoice: @invoice}) %>"); +$("#sepa_downloaded_multi_<%= @ordergroup_invoice.id %>").html("<%= escape_javascript(render partial: 'toggle_sepa_downloaded', locals: {ordergroup_invoice: @ordergroup_invoice}) %>"); diff --git a/config/environments/development.rb.SAMPLE b/config/environments/development.rb.SAMPLE index 40443e01..ed5bb855 100644 --- a/config/environments/development.rb.SAMPLE +++ b/config/environments/development.rb.SAMPLE @@ -36,9 +36,6 @@ Rails.application.configure do # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false - config.action_mailer.perform_deliveries = true - config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } - config.action_mailer.delivery_method = :letter_opener_web config.action_mailer.perform_caching = false @@ -60,12 +57,12 @@ Rails.application.configure do config.assets.initialize_on_precompile = true # Configure hostname for action mailer (can be overridden in foodcoop config) - config.action_mailer.default_url_options = { host: 'localhost', port: 3000} + config.action_mailer.default_url_options = { host: 'localhost', port: 3000, protocol: 'http' } # Mailcatcher config, start mailcatcher from console with 'mailcatcher' # Mailcatcher can be installed by gem install mailcatcher - #config.action_mailer.delivery_method = :smtp - #config.action_mailer.smtp_settings = { address: ENV.fetch("MAILCATCHER_ADDRESS", "localhost"), port: ENV.fetch("MAILCATCHER_PORT", 1025) } + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { address: ENV.fetch("MAILCATCHER_ADDRESS", "localhost"), port: ENV.fetch("MAILCATCHER_PORT", 1025) } # Raises error for missing translations # config.action_view.raise_on_missing_translations = true diff --git a/config/locales/de.yml b/config/locales/de.yml index 113df2f7..7b50fca7 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -101,7 +101,6 @@ de: actions_for_all: Aktion für alle ausführen delete: Rechnung löschen create_cumulative_invoice: Kumulative Rechnung erstellen - confirm_send_all: Möchtest Du wirklich diese Bestellgruppenrechnungen an %{ordergroups} versenden? combine: Rechnungen zusammenfassen download: Rechnung herunterladen download_all_zip: Alle Rechnungen herunterladen (zip) @@ -112,8 +111,6 @@ de: ordergroup: Bestellgruppe paid: Bezahlt not_paid: Nicht Bezahlt - send_all_by_email: Alle Rechnungen versenden - send_all_success: Rechnungen erfolgreich versendet sepa_downloaded: SEPA exportiert sepa_not_downloaded: SEPA nicht exportiert sepa_not_ready: @@ -198,9 +195,6 @@ de: last_user_activity: Zuletzt aktiv name: Name user_tokens: Mitglieder - ordergroup_invoice: - name: Bestellgruppenrechnung - email_sent: versendet am sepa_account_holder: bic: BIC holder: SEPA Kontoinhaber*in @@ -1399,15 +1393,6 @@ de: Im Anhang befindet sich daher eure Rechnung. Viele Grüße von %{foodcoop} - ordergroup_invoice: - subject: Bestellgruppenrechnung für %{group} bei %{supplier} - text: | - Liebe Bestellgruppe %{group}, - - Die Sammelbestellung bei %{supplier} wurde soeben abgerechnet und für die jeweiligen Bestellgruppen Rechnungen angelegt. - Im Anhang befindet sich daher eure Rechnung. - - Viele Grüße von %{foodcoop} invite: subject: Einladung in die Foodcoop text: | diff --git a/config/locales/en.yml b/config/locales/en.yml index 742dc116..ae1f3cc5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -91,7 +91,7 @@ en: total_price: Sum unit_price: Price/Unit group_order_invoice: - name: group-order-invoice + name: Group order invoice sequence_type: FRST: "First Direct Debit" RCUR: "Recurring Direct Debit" @@ -101,7 +101,6 @@ en: actions_for_all: Actions for all group orders create_cumulative_invoice: create cumulative invoice combine: combine invoices - confirm_send_all: Are you sure you want to send these ordergroup invoices to %{ordergroups}? delete: delete invoice download: download invoice download_all_zip: download all invoices as zip @@ -112,8 +111,6 @@ en: ordergroup: Ordergroup paid: paid not_paid: unpaid - send_all_by_email: send all invoices - send_all_success: Invoices were sent to all ordergroups sepa_downloaded: SEPA exported sepa_not_downloaded: SEPA not exported sepa_not_ready: Configurations for SEPA are missing in Admin->Settings->Finances @@ -197,9 +194,6 @@ en: last_user_activity: Last activity name: Name user_tokens: Members - ordergroup_invoice: - name: ordergroup-invoice - email_sent: Email sent at stock_article: available: Available price: Price @@ -1364,16 +1358,7 @@ en: header: "%{user} wrote at %{date}:" subject: Feedback for Foodsoft group_order_invoice: - subject: Group order invoice for %{group} at %{supplier} - text: | - Dear order group %{group}, - - The collective order at %{supplier} has just been settled and invoices have been created for the respective order groups. - Attached you will find your invoice. - - Best regards from %{foodcoop} - ordergroup_invoice: - subject: Group order invoice for %{group} at %{supplier} + subject: Order group invoice for %{group} at %{supplier} text: | Dear order group %{group}, diff --git a/config/routes.rb b/config/routes.rb index d1c9a160..9d839c04 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,11 +2,6 @@ Rails.application.routes.draw do mount Rswag::Ui::Engine => '/api-docs' mount Rswag::Api::Engine => '/api-docs' - - if Rails.env.development? - mount LetterOpenerWeb::Engine, at: "/letter_opener" - end - get 'order_comments/new' get 'comments/new' @@ -157,8 +152,7 @@ Rails.application.routes.draw do post 'finance/group_order_invoice', to: 'group_order_invoices#create_multiple' get 'orders/:order_id/group_order_invoices/download_all', to: 'group_order_invoices#download_all', as: 'download_all_group_order_invoices' - get 'multi_orders/:multi_order_id/ordergroup_invoices/download_all', to: 'ordergroup_invoices#download_all', as: 'download_all_ordergroup_invoices' - post 'multi_orders/:multi_order_id/ordergroup_invoices/send_all', to: 'ordergroup_invoices#send_all', as: 'send_all_ordergroup_invoices' + get 'multi_orders/:multi_order_id/group_order_invoices/download_all', to: 'ordergroup_invoices#download_all', as: 'download_all_ordergroup_invoices' resources :ordergroup_invoices do member do diff --git a/db/migrate/20250521134157_add_email_sent_to_ordergroup_invoice.rb b/db/migrate/20250521134157_add_email_sent_to_ordergroup_invoice.rb deleted file mode 100644 index 5b369e85..00000000 --- a/db/migrate/20250521134157_add_email_sent_to_ordergroup_invoice.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddEmailSentToOrdergroupInvoice < ActiveRecord::Migration[7.0] - def change - add_column :ordergroup_invoices, :email_sent_at, :datetime - end -end diff --git a/db/routes.rb b/db/routes.rb index efde401b..e0c41b48 100644 --- a/db/routes.rb +++ b/db/routes.rb @@ -162,7 +162,6 @@ Rails.application.routes.draw do end collection do get :download_within_date - get :send_all patch :select_all_sepa_sequence_type patch :toggle_all_sepa_downloaded patch :toggle_all_paid diff --git a/db/schema.rb b/db/schema.rb index e6d9fd05..51a2ac73 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2025_05_21_134157) do +ActiveRecord::Schema[7.0].define(version: 2025_05_16_104953) do create_table "action_text_rich_texts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.string "name", null: false t.text "body", size: :long @@ -407,7 +407,6 @@ ActiveRecord::Schema[7.0].define(version: 2025_05_21_134157) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "multi_group_order_id" - t.datetime "email_sent_at" t.index ["multi_group_order_id"], name: "index_ordergroup_invoices_on_multi_group_order_id" end diff --git a/db/seeds.rb b/db/seeds.rb index d34f28db..37a996ff 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,4 +1,4 @@ # default seed is minimal -require Rails.root.join('db/seeds/demo.seeds.rb') +require Rails.root.join('db/seeds/minimal.seeds.rb') # to generate new seeds, use the seed_dumper gem diff --git a/spec/factories/group_order.rb b/spec/factories/group_order.rb index 561edc11..d62172ea 100644 --- a/spec/factories/group_order.rb +++ b/spec/factories/group_order.rb @@ -5,6 +5,5 @@ FactoryBot.define do factory :group_order do ordergroup { create(:user, groups: [FactoryBot.create(:ordergroup)]).ordergroup } updated_by { create(:user) } - order end end diff --git a/spec/factories/multi_group_order.rb b/spec/factories/multi_group_order.rb deleted file mode 100644 index 0ca0f023..00000000 --- a/spec/factories/multi_group_order.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'factory_bot' - -FactoryBot.define do - factory :multi_group_order do - group_orders { [create(:group_order)] } - association :multi_order - end -end diff --git a/spec/factories/multi_order.rb b/spec/factories/multi_order.rb deleted file mode 100644 index f7814c68..00000000 --- a/spec/factories/multi_order.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'factory_bot' - -FactoryBot.define do - factory :multi_order do - transient do - orders { [create(:order, state: 'closed')] } - end - - after(:build) do |multi_order, evaluator| - # Assign orders before validation so custom validations can see them - multi_order.orders = evaluator.orders - end - - after(:create) do |multi_order, _evaluator| - # Persist the relationship by updating the orders (if needed) - multi_order.orders.each do |order| - order.update!(multi_order: multi_order) - end - end - end -end diff --git a/spec/factories/ordergroup_invoice.rb b/spec/factories/ordergroup_invoice.rb deleted file mode 100644 index c8b85ae7..00000000 --- a/spec/factories/ordergroup_invoice.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'factory_bot' - -FactoryBot.define do - factory :ordergroup_invoice do - multi_group_order { create :multi_group_order } - after(:build) { |ogi| ogi.init } - end -end diff --git a/spec/factories/sepa_account_holder.rb b/spec/factories/sepa_account_holder.rb deleted file mode 100644 index 945e4f6c..00000000 --- a/spec/factories/sepa_account_holder.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'factory_bot' - -FactoryBot.define do - factory :sepa_account_holder do - user { create :user } - group { create :ordergroup } - iban { "DE89370400440532013000" } - bic { "DEUTDEFF" } - mandate_id { "TEST-MANDATE-001" } - mandate_date_of_signature { Time.current } - end -end diff --git a/spec/integration/multi_order_spec.rb b/spec/integration/multi_order_spec.rb deleted file mode 100644 index cc0fa783..00000000 --- a/spec/integration/multi_order_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -require_relative '../spec_helper' - -feature MultiOrder, type: :feature, js: true do - let(:admin) { create :user, groups: [create(:workgroup, role_finance: true), create(:ordergroup, name: "AdminOrders")] } - let(:user) { create :user, groups: [create(:ordergroup)] } - - let(:article) { create :article, unit_quantity: 4 } - let(:article1) { create :article, unit_quantity: 2 } - let(:order) { create :order, supplier: article.supplier, article_ids: [article.id], ends: Time.now } - let(:order1) { create :order, supplier: article1.supplier, article_ids: [article1.id], ends: Time.now } - - let(:go) { create :group_order, order: order, ordergroup: user.ordergroup} - let(:go1) { create :group_order, order: order1, ordergroup: admin.ordergroup} - - let(:oa) { order.order_articles.find_by_article_id(article.id) } - let(:oa1) { order1.order_articles.find_by_article_id(article1.id) } - let(:ftt) { create :financial_transaction_type } - - let(:goa) { create :group_order_article, group_order: go, order_article: oa } - let(:goa1) { create :group_order_article, group_order: go1, order_article: oa1 } - - include ActiveJob::TestHelper - - before do - login admin - goa.update_quantities 2, 0 - goa1.update_quantities 2, 0 - oa.update_results! - oa1.update_results! - FoodsoftConfig[:contact][:tax_number] = 12_345_678 - order.update!(state: 'closed') - order1.update!(state: 'closed') - end - - after { clear_enqueued_jobs } - - # first ensure theres multiple orders and the check box to combine them to a multiorder - - it 'shows the elements to combine orders' do - visit finance_order_index_path - expect(page).to have_css("#order_#{order.id}_combine") - expect(page).to have_css("#order_#{order1.id}_combine") - expect(page).to have_css(".merge-orders-btn") - end - - it 'cannot combine orders when orders are not closed' do - order.update!(state: 'finished') - visit finance_order_index_path - expect(page).to have_css("#order_#{order.id}_combine") - expect(page).to have_css("#order_#{order1.id}_combine") - expect(page).to have_css(".merge-orders-btn") - # check the checkboxes and click the button - check("order_#{order.id}_combine") - check("order_#{order1.id}_combine") - click_link_or_button 'Zusammenführen' - expect(page).to have_content('Die Bestellung ist bereits Teil einer Multi-Bestellung oder ist noch nicht abgeschlossen.') - end - - it 'cannot combine orders when group_orders already have an invoice' do - group_order_invoice = create(:group_order_invoice, group_order: go) - visit finance_order_index_path - expect(page).to have_css("#order_#{order.id}_combine") - expect(page).to have_css("#order_#{order1.id}_combine") - expect(page).to have_css(".merge-orders-btn") - # check the checkboxes and click the button - check("order_#{order.id}_combine") - check("order_#{order1.id}_combine") - click_link_or_button 'Zusammenführen' - expect(page).to have_content('Zusammenführen nicht möglich. Es gibt bereits Rechnungen für einige der Bestellgruppen.') - end - - it 'combines orders into multi_order' do - visit finance_order_index_path - expect(MultiOrder.count).to eq(0) - check("order_#{order.id}_combine") - check("order_#{order1.id}_combine") - click_link_or_button 'Zusammenführen' - sleep 2 - expect(page).to have_content("Multi Bestellung für #{MultiOrder.last.name} erstellt") - expect(MultiOrder.count).to eq(1) - end -end diff --git a/spec/integration/ordergroup_invoice_spec.rb b/spec/integration/ordergroup_invoice_spec.rb deleted file mode 100644 index 6390b9b0..00000000 --- a/spec/integration/ordergroup_invoice_spec.rb +++ /dev/null @@ -1,162 +0,0 @@ -require_relative '../spec_helper' - -feature OrdergroupInvoice, type: :feature, js: true do - let(:admin) { create :user, groups: [create(:workgroup, role_finance: true), create(:ordergroup, name: "AdminOrders")] } - let(:user) { create :user, groups: [create(:ordergroup)] } - - let(:article) { create :article, unit_quantity: 4 } - let(:article1) { create :article, unit_quantity: 2 } - let(:order) { create :order, supplier: article.supplier, article_ids: [article.id], ends: Time.now } - let(:order1) { create :order, supplier: article1.supplier, article_ids: [article1.id], ends: Time.now } - - let(:go) { create :group_order, order: order, ordergroup: user.ordergroup} - let(:go1) { create :group_order, order: order1, ordergroup: admin.ordergroup} - - let(:oa) { order.order_articles.find_by_article_id(article.id) } - let(:oa1) { order1.order_articles.find_by_article_id(article1.id) } - let(:ftt) { create :financial_transaction_type } - - let(:goa) { create :group_order_article, group_order: go, order_article: oa } - let(:goa1) { create :group_order_article, group_order: go1, order_article: oa1 } - - include ActiveJob::TestHelper - - before do - login admin - goa.update_quantities 2, 0 - goa1.update_quantities 2, 0 - oa.update_results! - oa1.update_results! - FoodsoftConfig[:contact][:tax_number] = 12_345_678 - order.update!(state: 'closed') - order1.update!(state: 'closed') - end - - after { clear_enqueued_jobs } - - # first ensure theres multiple orders and the check box to combine them to a multiorder - - it 'shows the elements to combine orders' do - visit finance_order_index_path - expect(page).to have_css("#order_#{order.id}_combine") - expect(page).to have_css("#order_#{order1.id}_combine") - expect(page).to have_css(".merge-orders-btn") - end - - it 'cannot combine orders when orders are not closed' do - order.update!(state: 'finished') - visit finance_order_index_path - expect(page).to have_css("#order_#{order.id}_combine") - expect(page).to have_css("#order_#{order1.id}_combine") - expect(page).to have_css(".merge-orders-btn") - # check the checkboxes and click the button - check("order_#{order.id}_combine") - check("order_#{order1.id}_combine") - click_link_or_button 'Zusammenführen' - expect(page).to have_content('Die Bestellung ist bereits Teil einer Multi-Bestellung oder ist noch nicht abgeschlossen.') - end - - it 'cannot combine orders when group_orders already have an invoice' do - group_order_invoice = create(:group_order_invoice, group_order: go) - visit finance_order_index_path - expect(page).to have_css("#order_#{order.id}_combine") - expect(page).to have_css("#order_#{order1.id}_combine") - expect(page).to have_css(".merge-orders-btn") - # check the checkboxes and click the button - check("order_#{order.id}_combine") - check("order_#{order1.id}_combine") - click_link_or_button 'Zusammenführen' - expect(page).to have_content('Zusammenführen nicht möglich. Es gibt bereits Rechnungen für einige der Bestellgruppen.') - end - - it 'can generate multiple ordergroup invoice' do - multi_order = create(:multi_order, orders: [order, order1]) - visit finance_order_index_path - expect(page).to have_selector(:link_or_button, "Multi Bestellung auflösen") - click_link_or_button 'Toggle details' - expect(page).to have_selector(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.generate_with_date')) - click_link_or_button I18n.t('activerecord.attributes.group_order_invoice.links.generate_with_date') - sleep 1 - expect(OrdergroupInvoice.all.count).to eq(2) - end - - it 'can generate single ordergroup invoice' do - multi_order = create(:multi_order, orders: [order, order1]) - visit finance_order_index_path - expect(page).to have_selector(:link_or_button, "Multi Bestellung auflösen") - click_link_or_button 'Toggle details' - expect(page).to have_selector(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.generate')) - first(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.generate')).click - sleep 1 - expect(OrdergroupInvoice.all.count).to eq(1) - end - it 'cannot toggel details when config wrong' do - FoodsoftConfig[:contact][:tax_number] = nil - multi_order = create(:multi_order, orders: [order, order1]) - visit finance_order_index_path - expect(page).not_to have_selector(:link_or_button, 'Toggle details') - end - - it 'cannot destroy multi_order if invoice attached' do - multi_order = create(:multi_order, orders: [order, order1]) - visit finance_order_index_path - expect(page).to have_selector(:link_or_button, "Multi Bestellung auflösen") - click_link_or_button 'Toggle details' - expect(page).to have_selector(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.generate')) - sleep 1 - first(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.generate')).click - sleep 1 - expect(OrdergroupInvoice.all.count).to eq(1) - click_link_or_button 'Multi Bestellung auflösen' - expect(page).to have_content("Lösche erst die Rechnungen") - end - - it 'can toggle elements for ordergroup invoice' do - multi_order = create(:multi_order, orders: [order, order1]) - visit finance_order_index_path - expect(page).to have_selector(:link_or_button, "Multi Bestellung auflösen") - click_link_or_button 'Toggle details' - expect(page).to have_selector(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.generate_with_date')) - click_link_or_button I18n.t('activerecord.attributes.group_order_invoice.links.generate_with_date') - sleep 1 - expect(OrdergroupInvoice.all.count).to eq(2) - - expect(page).not_to have_checked_field("sepa_downloaded_multi_#{OrdergroupInvoice.last.id}") - - #check boxes sepa downloaded - check("sepa_downloaded_all_multi_#{multi_order.id}") - sleep 1 - expect(page).to have_checked_field("sepa_downloaded_multi_#{OrdergroupInvoice.last.id}") - expect(page).to have_checked_field("sepa_downloaded_multi_#{OrdergroupInvoice.first.id}") - check("paid_all_multi_#{multi_order.id}") - expect(page).to have_checked_field("paid_multi_#{OrdergroupInvoice.first.id}") - expect(page).to have_checked_field("paid_multi_#{OrdergroupInvoice.last.id}") - - - #sepa selects - select_box = find("#all_sepa_sequence_type_multi_#{multi_order.id}") - expect(select_box.value).to eq("RCUR") - expect(find("#sepa_sequence_type_multi_#{OrdergroupInvoice.last.id}").value).to eq("RCUR") - select "Erst-Lastschrift", from: "sepa_sequence_type_multi_#{OrdergroupInvoice.last.id}" - sleep 1 - expect(find("#sepa_sequence_type_multi_#{OrdergroupInvoice.last.id}").value).to eq("FRST") - end - - it 'downloads sepa and toggles checkboxes' do - multi_order = create(:multi_order, orders: [order, order1]) - sepa_account_holder = create(:sepa_account_holder, user: admin, group: admin.ordergroup) - FoodsoftConfig[:group_order_invoices] = {iban: "DE89370400440532013000", bic: "DEUTDEFF", creditor_identifier:"DE98ZZZ09999999999"} - visit finance_order_index_path - expect(page).to have_selector(:link_or_button, "Multi Bestellung auflösen") - click_link_or_button 'Toggle details' - expect(page).to have_selector(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.generate_with_date')) - click_link_or_button I18n.t('activerecord.attributes.group_order_invoice.links.generate_with_date') - sleep 1 - expect(OrdergroupInvoice.all.count).to eq(2) - expect(page).to have_selector(:link_or_button, I18n.t('activerecord.attributes.group_order_invoice.links.download')) - # admin is the last multi_group_order - multi_group_order = multi_order.multi_group_orders.last - check("group_order_#{multi_group_order.id}_included_in_sepa") - expect(page).to have_selector(:link_or_button, 'Sammellastschrift für ausgewählt (.xml)') - end -end diff --git a/spec/models/group_order_invoice_spec.rb b/spec/models/group_order_invoice_spec.rb index e2349838..24bfcf7e 100644 --- a/spec/models/group_order_invoice_spec.rb +++ b/spec/models/group_order_invoice_spec.rb @@ -43,7 +43,7 @@ describe GroupOrderInvoice do it 'fails to create if group_order_id is used multiple times for creation' do expect(goi1.group_order.id).to eq(group_order.id) - expect { goi2 }.to raise_error(ActiveRecord::RecordInvalid) + expect { goi2 }.to raise_error(ActiveRecord::RecordNotUnique) end it 'creates two different group order invoice with different invoice_numbers' do diff --git a/spec/models/multi_group_order_spec.rb b/spec/models/multi_group_order_spec.rb deleted file mode 100644 index 58250750..00000000 --- a/spec/models/multi_group_order_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require_relative '../spec_helper' -describe MultiGroupOrder do - let(:admin) { create :user, groups: [create(:workgroup, role_finance: true), create(:ordergroup, name: "AdminOrders")] } - let(:user) { create :user, groups: [create(:ordergroup)] } - - let(:article1) { create :article, unit_quantity: 1 } - let(:article2) { create :article, unit_quantity: 3 } - - context 'does not generate Multi Group Order without valid multi_order' do - it 'when orders are not closed' do - order1 = create :order, multi_order: nil - order2 = create :order, multi_order: nil - group_order1 = create :group_order, ordergroup: user.ordergroup, order: order1 - group_order2 = create :group_order, ordergroup: user.ordergroup, order: order2 - expect { create(:multi_order, orders:[order1, order2]) }.to raise_error(ActiveRecord::RecordInvalid) - expect(MultiGroupOrder.count).to eq(0) - end - end - context 'Multi Group Order is created by MultiOrder' do - it 'when orders are closed' do - order1 = create :order, multi_order: nil - order2 = create :order, multi_order: nil - group_order1 = create :group_order, ordergroup: user.ordergroup, order: order1 - group_order2 = create :group_order, ordergroup: user.ordergroup, order: order2 - order1.update!(state: 'closed') - order2.update!(state: 'closed') - multi_order = create(:multi_order, orders: [order1, order2]) - expect(MultiGroupOrder.count).to eq(1) - end - end -end \ No newline at end of file diff --git a/spec/models/multi_order_spec.rb b/spec/models/multi_order_spec.rb deleted file mode 100644 index c96c8128..00000000 --- a/spec/models/multi_order_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -require_relative '../spec_helper' -describe MultiOrder do - let(:admin) { create :user, groups: [create(:workgroup, role_finance: true), create(:ordergroup, name: "AdminOrders")] } - let(:user) { create :user, groups: [create(:ordergroup)] } - - let(:article1) { create :article, unit_quantity: 1 } - let(:article2) { create :article, unit_quantity: 3 } - - context 'does not generate Multi Order' do - let(:order1) { create :order } - let(:order2) { create :order} - let!(:group_order1) { create :group_order, ordergroup: user.ordergroup, order: order1 } - let!(:group_order2) { create :group_order, ordergroup: user.ordergroup, order: order2 } - let!(:group_order3) { create :group_order, ordergroup: admin.ordergroup, order: order1 } - - before do - order1.update!(state: 'open') - order2.update!(state: 'open') - FoodsoftConfig[:contact][:tax_number] = 123_457_8 - end - - it 'when orders are not closed' do - expect { create(:multi_order, orders: [order1]) }.to raise_error(ActiveRecord::RecordInvalid) - end - - it 'when orders are not finished' do - expect { create(:multi_order, orders: [order2]) }.to raise_error(ActiveRecord::RecordInvalid) - end - - - it 'when group order invoices are present' do - order1.update!(state: 'closed') - order2.update!(state: 'closed') - group_order1.update!(group_order_invoice: create(:group_order_invoice)) - group_order2.update!(group_order_invoice: create(:group_order_invoice)) - expect { create(:multi_order, orders: [order1, order2]) }.to raise_error(ActiveRecord::RecordInvalid) - end - end - - context 'generates Multi Order' do - - let(:order3) { create :order, multi_order: nil } - let(:order4) { create :order, multi_order: nil } - let(:order5) { create :order, multi_order: nil } - - let!(:group_order1) { create :group_order, ordergroup: user.ordergroup, order: order3 } - let!(:group_order2) { create :group_order, ordergroup: user.ordergroup, order: order4 } - let!(:group_order3) { create :group_order, ordergroup: admin.ordergroup, order: order5 } - let!(:group_order4) { create :group_order, ordergroup: admin.ordergroup, order: order4 } - - before do - order3.update!(state: 'closed') - order4.update!(state: 'closed') - order5.update!(state: 'closed') - end - - it 'when orders are closed' do - #as it is right now orders can be in multiple multi orders - # expect(create(:multi_order, orders: [order3])).to be_valid - expect(create(:multi_order, orders: [order3])).to be_valid - end - - it 'when group order invoices are not present' do - multi_order2 = create(:multi_order, orders: [order3, order4]) - expect(multi_order2).to be_valid - end - end -end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 59a47b9a..ec5e7a35 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,8 +19,6 @@ end # in spec/support/ and its subdirectories. Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } -ActiveRecord::Migration.maintain_test_schema! - RSpec.configure do |config| # We use capybara with webkit, and need database_cleaner config.before do