From 10f054256e832e877e01ddf36e1d755087cdc5d0 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 5 Jan 2023 12:09:16 +0100 Subject: [PATCH] (feat) payment schedule due in invoices --- CHANGELOG.md | 1 + app/models/invoice.rb | 4 +- app/pdfs/pdf/invoice.rb | 136 ++---------------- app/services/invoices/item_label_service.rb | 92 ++++++++++++ app/services/invoices/label_service.rb | 19 ++- .../invoices/payment_details_service.rb | 79 ++++++++++ app/services/invoices/recipient_service.rb | 6 + app/workers/invoice_worker.rb | 5 +- app/workers/payment_schedule_item_worker.rb | 12 +- config/locales/app.logged.fr.yml | 2 +- config/locales/app.logged.zu.yml | 22 +-- config/locales/de.yml | 1 + config/locales/en.yml | 1 + config/locales/es.yml | 1 + config/locales/fr.yml | 1 + config/locales/no.yml | 1 + config/locales/pt.yml | 1 + config/locales/zu.yml | 1 + test/helpers/invoice_helper.rb | 2 +- 19 files changed, 233 insertions(+), 154 deletions(-) create mode 100644 app/services/invoices/item_label_service.rb create mode 100644 app/services/invoices/payment_details_service.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index a6a5e53cd..84f7daabd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Display custom error message if the PDF invoice is not found - Report subsription mismatch with user's group - Added sentry for error reporting +- Report details of the due for invoices related to a payment schedule - Fix a bug: unable to run test in negative timezones (#425) - Fix a bug: providing an array of attributes to filter OpenApi data, results in error - Fix a bug: unable to manage stocks on new products diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 3edc9f54b..1e31cf7ab 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -54,7 +54,7 @@ class Invoice < PaymentDocument # for debug & used by rake task "fablab:maintenance:regenerate_invoices" def regenerate_invoice_pdf - pdf = ::PDF::Invoice.new(self, invoice_items.find_by(object_type: Subscription.name)&.object&.expiration_date).render + pdf = ::PDF::Invoice.new(self).render File.binwrite(file, pdf) end @@ -199,7 +199,7 @@ class Invoice < PaymentDocument "main_item.object_id(#{main_item.object_id}), " \ "main_item.object_type(#{main_item.object_type}), user_id(#{invoicing_profile.user_id})" end - InvoiceWorker.perform_async(id, user&.subscription&.expired_at) + InvoiceWorker.perform_async(id) end def log_changes diff --git a/app/pdfs/pdf/invoice.rb b/app/pdfs/pdf/invoice.rb index 603ccc022..493346fdd 100644 --- a/app/pdfs/pdf/invoice.rb +++ b/app/pdfs/pdf/invoice.rb @@ -6,7 +6,8 @@ class PDF::Invoice < Prawn::Document include ActionView::Helpers::NumberHelper include ApplicationHelper - def initialize(invoice, subscription_expiration_date) + # @param invoice [Invoice] + def initialize(invoice) super(margin: 70) # fonts @@ -42,8 +43,8 @@ class PDF::Invoice < Prawn::Document text I18n.t('invoices.invoice_reference', REF: invoice.reference), leading: 3 end text I18n.t('invoices.code', CODE: Setting.get('invoice_code-value')), leading: 3 if Setting.get('invoice_code-active') - if invoice.main_item.object_type != WalletTransaction.name - order_number = invoice.main_item.object_type == OrderItem.name ? invoice.main_item.object.order.reference : invoice.order_number + if invoice.main_item&.object_type != WalletTransaction.name + order_number = invoice.main_item&.object_type == OrderItem.name ? invoice.main_item&.object&.order&.reference : invoice.order_number text I18n.t('invoices.order_number', NUMBER: order_number), leading: 3 end if invoice.is_a?(Avoir) @@ -80,60 +81,7 @@ class PDF::Invoice < Prawn::Document invoice.invoice_items.each do |item| price = item.amount.to_i / 100.00 - details = invoice.is_a?(Avoir) ? "#{I18n.t('invoices.cancellation')} - " : '' - - if item.object_type == Subscription.name - subscription = item.object - if invoice.main_item.object_type == 'OfferDay' - details += I18n.t('invoices.subscription_extended_for_free_from_START_to_END', - START: I18n.l(invoice.main_item.object.start_at.to_date), - END: I18n.l(invoice.main_item.object.end_at.to_date)) - else - subscription_end_at = case subscription_expiration_date - when Time - subscription_expiration_date - when String - DateTime.parse(subscription_expiration_date) - else - subscription.expiration_date - end - subscription_start_at = subscription_end_at - subscription.plan.duration - details += I18n.t('invoices.subscription_NAME_from_START_to_END', - NAME: item.description, - START: I18n.l(subscription_start_at.to_date), - END: I18n.l(subscription_end_at.to_date)) - end - - elsif item.object_type == Reservation.name - case invoice.main_item.object.try(:reservable_type) - ### Machine reservation - when 'Machine' - details += I18n.t('invoices.machine_reservation_DESCRIPTION', DESCRIPTION: item.description) - when 'Space' - details += I18n.t('invoices.space_reservation_DESCRIPTION', DESCRIPTION: item.description) - ### Training reservation - when 'Training' - details += I18n.t('invoices.training_reservation_DESCRIPTION', DESCRIPTION: item.description) - ### events reservation - when 'Event' - details += I18n.t('invoices.event_reservation_DESCRIPTION', DESCRIPTION: item.description) - # details of the number of tickets - if invoice.main_item.object.nb_reserve_places.positive? - details += "\n #{I18n.t('invoices.full_price_ticket', count: invoice.main_item.object.nb_reserve_places)}" - end - invoice.main_item.object.tickets.each do |t| - details += "\n #{I18n.t('invoices.other_rate_ticket', - count: t.booked, - NAME: t.event_price_category.price_category.name)}" - end - else - details += item.description - end - else - details += item.description - end - - data += [[details, number_to_currency(price)]] + data += [[Invoices::ItemLabelService.build(invoice, item), number_to_currency(price)]] total_calc += price total_ht += item.net_amount total_vat += item.vat @@ -221,71 +169,18 @@ class PDF::Invoice < Prawn::Document # payment details move_down 20 - if invoice.is_a?(Avoir) - payment_verbose = "#{I18n.t('invoices.refund_on_DATE', DATE: I18n.l(invoice.avoir_date.to_date))} " - case invoice.payment_method - when 'stripe' - payment_verbose += I18n.t('invoices.by_card_online_payment') - when 'cheque' - payment_verbose += I18n.t('invoices.by_cheque') - when 'transfer' - payment_verbose += I18n.t('invoices.by_transfer') - when 'cash' - payment_verbose += I18n.t('invoices.by_cash') - when 'wallet' - payment_verbose += I18n.t('invoices.by_wallet') - when 'none' - payment_verbose = I18n.t('invoices.no_refund') - else - Rails.logger.error "specified refunding method (#{payment_verbose}) is unknown" - end - payment_verbose += " #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))}" - else - # subtract the wallet amount for this invoice from the total - if invoice.wallet_amount - wallet_amount = invoice.wallet_amount / 100.00 - total -= wallet_amount - else - wallet_amount = nil - end - - # payment method - payment_verbose = if invoice.paid_by_card? - I18n.t('invoices.settlement_by_debit_card') - else - I18n.t('invoices.settlement_done_at_the_reception') - end - - # if the invoice was 100% payed with the wallet ... - payment_verbose = I18n.t('invoices.settlement_by_wallet') if total.zero? && wallet_amount - - payment_verbose += " #{I18n.t('invoices.on_DATE_at_TIME', - DATE: I18n.l(invoice.created_at.to_date), - TIME: I18n.l(invoice.created_at, format: :hour_minute))}" - if total.positive? || !invoice.wallet_amount - payment_verbose += " #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))}" - end - if invoice.wallet_amount - payment_verbose += if total.positive? - " #{I18n.t('invoices.and')} #{I18n.t('invoices.by_wallet')} " \ - "#{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))}" - else - " #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))}" - end - end - end - text payment_verbose + text Invoices::PaymentDetailsService.build(invoice, total) # important information move_down 40 - txt = parse_html(Setting.get('invoice_text')) + txt = parse_html(Setting.get('invoice_text').to_s) txt.each_line do |line| text line, style: :bold, inline_format: true end # address and legals information move_down 40 - txt = parse_html(Setting.get('invoice_legals')) + txt = parse_html(Setting.get('invoice_legals').to_s) txt.each_line do |line| text line, align: :right, leading: 4, inline_format: true end @@ -303,21 +198,6 @@ class PDF::Invoice < Prawn::Document private - def reservation_dates_verbose(slot) - if slot.start_at.to_date == slot.end_at.to_date - "- #{I18n.t('invoices.on_DATE_from_START_to_END', - DATE: I18n.l(slot.start_at.to_date), - START: I18n.l(slot.start_at, format: :hour_minute), - END: I18n.l(slot.end_at, format: :hour_minute))}\n" - else - "- #{I18n.t('invoices.from_STARTDATE_to_ENDDATE_from_STARTTIME_to_ENDTIME', - STARTDATE: I18n.l(slot.start_at.to_date), - ENDDATE: I18n.l(slot.start_at.to_date), - STARTTIME: I18n.l(slot.start_at, format: :hour_minute), - ENDTIME: I18n.l(slot.end_at, format: :hour_minute))}\n" - end - end - ## # Remove every unsupported html tag from the given html text (like

, , ...). # The supported tags are , , and
. diff --git a/app/services/invoices/item_label_service.rb b/app/services/invoices/item_label_service.rb new file mode 100644 index 000000000..ce83dc4ed --- /dev/null +++ b/app/services/invoices/item_label_service.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +# module definition +module Invoices; end + +# Build a label for the given invoice item +class Invoices::ItemLabelService + class << self + # @param invoice [Invoice] + # @param item [InvoiceItem] + # @return [String] + def build(invoice, item) + details = invoice.is_a?(Avoir) ? "#{I18n.t('invoices.cancellation')} - " : '' + + if item.object_type == Subscription.name + "#{details}#{build_subscription_label(invoice, item)}" + elsif item.object_type == Reservation.name + "#{details}#{build_reservation_label(invoice, item)}" + else + "#{details}#{item.description}" + end + end + + private + + # @param invoice [Invoice] + # @param item [InvoiceItem] + # @return [String] + def build_subscription_label(invoice, item) + subscription = item.object + label = if invoice.main_item&.object_type == 'OfferDay' + I18n.t('invoices.subscription_extended_for_free_from_START_to_END', + START: I18n.l(invoice.main_item&.object&.start_at&.to_date), + END: I18n.l(invoice.main_item&.object&.end_at&.to_date)) + else + subscription_end_at = subscription.expiration_date + subscription_start_at = subscription_end_at - subscription.plan.duration + I18n.t('invoices.subscription_NAME_from_START_to_END', + NAME: item.description, + START: I18n.l(subscription_start_at.to_date), + END: I18n.l(subscription_end_at.to_date)) + end + unless invoice.payment_schedule_item.nil? + dues = invoice.payment_schedule_item.payment_schedule.payment_schedule_items.order(:due_date) + label += "\n #{I18n.t('invoices.from_payment_schedule', + NUMBER: dues.index(invoice.payment_schedule_item) + 1, + TOTAL: dues.count, + DATE: I18n.l(invoice.payment_schedule_item.due_date.to_date), + SCHEDULE: invoice.payment_schedule_item.payment_schedule.reference)}" + end + label + end + + # @param invoice [Invoice] + # @param item [InvoiceItem] + # @return [String] + def build_reservation_label(invoice, item) + case invoice.main_item&.object.try(:reservable_type) + ### Machine reservation + when 'Machine' + I18n.t('invoices.machine_reservation_DESCRIPTION', DESCRIPTION: item.description) + when 'Space' + I18n.t('invoices.space_reservation_DESCRIPTION', DESCRIPTION: item.description) + ### Training reservation + when 'Training' + I18n.t('invoices.training_reservation_DESCRIPTION', DESCRIPTION: item.description) + ### events reservation + when 'Event' + build_event_reservation_label(invoice, item) + else + item.description + end + end + + # @param invoice [Invoice] + # @param item [InvoiceItem] + # @return [String] + def build_event_reservation_label(invoice, item) + label = I18n.t('invoices.event_reservation_DESCRIPTION', DESCRIPTION: item.description) + # details of the number of tickets + if invoice.main_item&.object&.nb_reserve_places&.positive? + label += "\n #{I18n.t('invoices.full_price_ticket', count: invoice.main_item&.object&.nb_reserve_places)}" + end + invoice.main_item&.object&.tickets&.each do |t| + label += "\n #{I18n.t('invoices.other_rate_ticket', + count: t.booked, + NAME: t.event_price_category.price_category.name)}" + end + label + end + end +end diff --git a/app/services/invoices/label_service.rb b/app/services/invoices/label_service.rb index fbd1dd604..b5a7ab01a 100644 --- a/app/services/invoices/label_service.rb +++ b/app/services/invoices/label_service.rb @@ -6,12 +6,14 @@ module Invoices; end # Build a label for the given invoice class Invoices::LabelService class << self + # @param invoice [Invoice] + # @return [String, nil] def build(invoice) username = Invoices::RecipientService.name(invoice) if invoice.is_a?(Avoir) avoir_label(invoice) else - case invoice.main_item.object_type + case invoice.main_item&.object_type when 'Reservation' reservation_invoice_label(invoice, username) when 'Subscription' @@ -25,7 +27,7 @@ class Invoices::LabelService when 'OrderItem' I18n.t('invoices.order') else - Rails.logger.error "specified main_item.object_type type (#{invoice.main_item.object_type}) is unknown" + Rails.logger.error "specified main_item.object_type type (#{invoice.main_item&.object_type}) is unknown" nil end end @@ -33,12 +35,17 @@ class Invoices::LabelService private + # @param invoice [Invoice] + # @return [String] def avoir_label(invoice) - return I18n.t('invoices.wallet_credit') if invoice.main_item.object_type == WalletTransaction.name + return I18n.t('invoices.wallet_credit') if invoice.main_item&.object_type == WalletTransaction.name I18n.t('invoices.cancellation_of_invoice_REF', REF: invoice.invoice.reference) end + # @param invoice [Invoice] + # @param username [String] + # @return [String] def reservation_invoice_label(invoice, username) label = I18n.t('invoices.reservation_of_USER_on_DATE_at_TIME', USER: username, @@ -55,6 +62,9 @@ class Invoices::LabelService label end + # @param subscription [Subscription] + # @param username [String] + # @return [String] def subscription_label(subscription, username) subscription_start_at = subscription.expired_at - subscription.plan.duration duration_verbose = I18n.t("duration.#{subscription.plan.interval}", count: subscription.plan.interval_count) @@ -64,6 +74,9 @@ class Invoices::LabelService DATE: I18n.l(subscription_start_at.to_date)) end + # @param offer_day [OfferDay] + # @param username [String] + # @return [String] def offer_day_label(offer_day, username) I18n.t('invoices.subscription_of_NAME_extended_starting_from_STARTDATE_until_ENDDATE', NAME: username, diff --git a/app/services/invoices/payment_details_service.rb b/app/services/invoices/payment_details_service.rb new file mode 100644 index 000000000..726c84f71 --- /dev/null +++ b/app/services/invoices/payment_details_service.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +# module definition +module Invoices; end + +# Build a localized string detailing the payment mean for the given invoice +class Invoices::PaymentDetailsService + class << self + include ActionView::Helpers::NumberHelper + + # @param invoice [Invoice] + # @param total [Float] + # @return [String] + def build(invoice, total) + if invoice.is_a?(Avoir) + build_avoir_details(invoice) + else + # subtract the wallet amount for this invoice from the total + if invoice.wallet_amount + wallet_amount = invoice.wallet_amount / 100.00 + total -= wallet_amount + else + wallet_amount = nil + end + + # payment method + payment_verbose = if invoice.paid_by_card? + I18n.t('invoices.settlement_by_debit_card') + else + I18n.t('invoices.settlement_done_at_the_reception') + end + + # if the invoice was 100% payed with the wallet ... + payment_verbose = I18n.t('invoices.settlement_by_wallet') if total.zero? && wallet_amount + + payment_verbose += " #{I18n.t('invoices.on_DATE_at_TIME', + DATE: I18n.l(invoice.created_at.to_date), + TIME: I18n.l(invoice.created_at, format: :hour_minute))}" + if total.positive? || !invoice.wallet_amount + payment_verbose += " #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))}" + end + if invoice.wallet_amount + payment_verbose += if total.positive? + " #{I18n.t('invoices.and')} #{I18n.t('invoices.by_wallet')} " \ + "#{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))}" + else + " #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))}" + end + end + payment_verbose + end + end + + private + + # @param invoice [Invoice] + # @return [String] + def build_avoir_details(invoice) + details = "#{I18n.t('invoices.refund_on_DATE', DATE: I18n.l(invoice.avoir_date.to_date))} " + case invoice.payment_method + when 'stripe' + details += I18n.t('invoices.by_card_online_payment') + when 'cheque' + details += I18n.t('invoices.by_cheque') + when 'transfer' + details += I18n.t('invoices.by_transfer') + when 'cash' + details += I18n.t('invoices.by_cash') + when 'wallet' + details += I18n.t('invoices.by_wallet') + when 'none' + details = I18n.t('invoices.no_refund') + else + Rails.logger.error "specified refunding method (#{details}) is unknown" + end + "#{details} #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))}" + end + end +end diff --git a/app/services/invoices/recipient_service.rb b/app/services/invoices/recipient_service.rb index fc57073a1..4e64440a4 100644 --- a/app/services/invoices/recipient_service.rb +++ b/app/services/invoices/recipient_service.rb @@ -7,6 +7,8 @@ module Invoices; end class Invoices::RecipientService class << self # Get the full name of the recipient for the given invoice. + # @param invoice [Invoice] + # @return [String] def name(invoice) if invoice.invoicing_profile.organization name = invoice.invoicing_profile.organization.name @@ -17,11 +19,15 @@ class Invoices::RecipientService end # Get the street address of the recipient for the given invoice. + # @param invoice [Invoice] + # @return [String] def address(invoice) invoice.invoicing_profile&.invoicing_address end # Get the optional data in profile_custom_fields, if the recipient is an organization + # @param invoice [Invoice] + # @return [Array] def organization_data(invoice) return unless invoice.invoicing_profile.organization diff --git a/app/workers/invoice_worker.rb b/app/workers/invoice_worker.rb index 094ee9af2..25901d0f8 100644 --- a/app/workers/invoice_worker.rb +++ b/app/workers/invoice_worker.rb @@ -4,10 +4,10 @@ class InvoiceWorker include Sidekiq::Worker - def perform(invoice_id, subscription_expiration_date) + def perform(invoice_id) # generate a invoice invoice = Invoice.find invoice_id - pdf = ::PDF::Invoice.new(invoice, subscription_expiration_date).render + pdf = ::PDF::Invoice.new(invoice).render # store invoice on drive File.binwrite(invoice.file, pdf) @@ -23,5 +23,4 @@ class InvoiceWorker attached_object: invoice end end - end diff --git a/app/workers/payment_schedule_item_worker.rb b/app/workers/payment_schedule_item_worker.rb index 6579d1f46..74b2adcbc 100644 --- a/app/workers/payment_schedule_item_worker.rb +++ b/app/workers/payment_schedule_item_worker.rb @@ -10,12 +10,13 @@ class PaymentScheduleItemWorker psi = PaymentScheduleItem.find(record_id) check_item(psi) else - PaymentScheduleItem.where.not(state: 'paid').where('due_date < ?', DateTime.current).each do |psi| - check_item(psi) + PaymentScheduleItem.where.not(state: 'paid').where('due_date < ?', DateTime.current).each do |item| + check_item(item) end end end + # @param psi [PaymentScheduleItem] def check_item(psi) # the following depends on the payment method (card/check) if psi.payment_schedule.payment_method == 'card' @@ -26,9 +27,10 @@ class PaymentScheduleItemWorker NotificationCenter.call type: "notify_admin_payment_schedule_#{psi.payment_schedule.payment_method}_deadline", receiver: User.admins_and_managers, attached_object: psi - psi.update_attributes(state: 'pending') + psi.update(state: 'pending') end - rescue StandardError - psi.update_attributes(state: 'error') + rescue StandardError => e + Rails.logger.debug(e.backtrace) + psi.update(state: 'error') end end diff --git a/config/locales/app.logged.fr.yml b/config/locales/app.logged.fr.yml index 36d237227..011c11ec3 100644 --- a/config/locales/app.logged.fr.yml +++ b/config/locales/app.logged.fr.yml @@ -155,7 +155,7 @@ fr: credits_panel: title_Space: "Mes crédits espace" title_Machine: "Mes crédits machine" - reamaining_credits_html: "{NAME} : Vous pouvez réserver gratuitement {REMAINING} {REMAINING, plural, =0{créneau} one{créneau} other{créneaux}}. Vous avez déjà utilisé {USED} {USED, plural, =0{crédit} one{crédit} other{crédits}} de votre abonnement actuel." + reamaining_credits_html: "{NAME} : Vous pouvez réserver gratuitement {REMAINING} {REMAINING, plural, one{créneau} other{créneaux}}. Vous avez déjà utilisé {USED} {USED, plural, one{crédit} other{crédits}} de votre abonnement actuel." no_credits: "Vous n'avez pas encore de crédits. Certains abonnements peuvent vous permettre de réserver des créneaux gratuitement." #public profil of a member members_show: diff --git a/config/locales/app.logged.zu.yml b/config/locales/app.logged.zu.yml index bab47f7ac..46a78bee3 100644 --- a/config/locales/app.logged.zu.yml +++ b/config/locales/app.logged.zu.yml @@ -145,18 +145,18 @@ zu: edit: "crwdns27632:0crwdne27632:0" reservations: reservations_panel: - title_Space: "crwdns27634:0crwdne27634:0" - title_Machine: "crwdns27636:0crwdne27636:0" - upcoming: "crwdns27638:0crwdne27638:0" - past: "crwdns27640:0crwdne27640:0" - slots_details: "crwdns27642:0crwdne27642:0" - no_reservations: "crwdns27644:0crwdne27644:0" - show_more: "crwdns27646:0crwdne27646:0" + title_Space: "crwdns36333:0crwdne36333:0" + title_Machine: "crwdns36335:0crwdne36335:0" + upcoming: "crwdns36337:0crwdne36337:0" + past: "crwdns36339:0crwdne36339:0" + slots_details: "crwdns36341:0crwdne36341:0" + no_reservations: "crwdns36343:0crwdne36343:0" + show_more: "crwdns36345:0crwdne36345:0" credits_panel: - title_Space: "crwdns27648:0crwdne27648:0" - title_Machine: "crwdns27650:0crwdne27650:0" - reamaining_credits_html: "crwdns27652:0NAME={NAME}crwdnd27652:0REMAINING={REMAINING}crwdnd27652:0REMAINING={REMAINING}crwdnd27652:0USED={USED}crwdnd27652:0USED={USED}crwdne27652:0" - no_credits: "crwdns27654:0crwdne27654:0" + title_Space: "crwdns36347:0crwdne36347:0" + title_Machine: "crwdns36349:0crwdne36349:0" + reamaining_credits_html: "crwdns36351:0NAME={NAME}crwdnd36351:0REMAINING={REMAINING}crwdnd36351:0REMAINING={REMAINING}crwdnd36351:0USED={USED}crwdnd36351:0USED={USED}crwdne36351:0" + no_credits: "crwdns36353:0crwdne36353:0" #public profil of a member members_show: members_list: "crwdns27656:0crwdne27656:0" diff --git a/config/locales/de.yml b/config/locales/de.yml index 41d07cf2c..d986bf938 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -98,6 +98,7 @@ de: space_reservation_DESCRIPTION: "Raumreservierung - %{DESCRIPTION}" training_reservation_DESCRIPTION: "Trainingsreservierung - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Veranstaltungs-Reservierung - %{DESCRIPTION}" + from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" full_price_ticket: one: "Ein Vollpreis-Ticket" other: "%{count} Vollpreis-Tickets" diff --git a/config/locales/en.yml b/config/locales/en.yml index c42a0dc9e..27d4cd98c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -98,6 +98,7 @@ en: space_reservation_DESCRIPTION: "Space reservation - %{DESCRIPTION}" training_reservation_DESCRIPTION: "Training reservation - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Event reservation - %{DESCRIPTION}" + from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" full_price_ticket: one: "One full price ticket" other: "%{count} full price tickets" diff --git a/config/locales/es.yml b/config/locales/es.yml index 55029808b..9f1ef8fee 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -98,6 +98,7 @@ es: space_reservation_DESCRIPTION: "Reserva de espacio - %{DESCRIPTION}" training_reservation_DESCRIPTION: "Reserva de curso - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Reserva de evento - %{DESCRIPTION}" + from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" full_price_ticket: one: "Una entrada de precio completo" other: "%{count} entradas de precio completo" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index f342c868f..2764b5124 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -98,6 +98,7 @@ fr: space_reservation_DESCRIPTION: "Réservation Espace - %{DESCRIPTION}" training_reservation_DESCRIPTION: "Réservation Formation - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Réservation Événement - %{DESCRIPTION}" + from_payment_schedule: "Échéance %{NUMBER} sur %{TOTAL}, du %{DATE}. Échéancier de paiement %{SCHEDULE}" full_price_ticket: one: "Une place plein tarif" other: "%{count} places plein tarif" diff --git a/config/locales/no.yml b/config/locales/no.yml index cfd180fd2..6fcbc42e9 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -98,6 +98,7 @@ space_reservation_DESCRIPTION: "Reservasjon av plass/rom - %{DESCRIPTION}" training_reservation_DESCRIPTION: "Bestilling, opplæring/kurs - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Arrangements-reservasjon - %{DESCRIPTION}" + from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" full_price_ticket: one: "En fullprisbillett" other: "%{count} full price tickets" diff --git a/config/locales/pt.yml b/config/locales/pt.yml index b5e36fe8a..70ed4b8c5 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -98,6 +98,7 @@ pt: space_reservation_DESCRIPTION: "Reserva de máquina - %{DESCRIPTION}" training_reservation_DESCRIPTION: "Reserva de treinamneto - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Reserva de evento - %{DESCRIPTION}" + from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" full_price_ticket: one: "Um ticket de preço cheio" other: "%{count} tickets de preço cheio" diff --git a/config/locales/zu.yml b/config/locales/zu.yml index 953d7b078..a62c04b6c 100644 --- a/config/locales/zu.yml +++ b/config/locales/zu.yml @@ -98,6 +98,7 @@ zu: space_reservation_DESCRIPTION: "crwdns3319:0%{DESCRIPTION}crwdne3319:0" training_reservation_DESCRIPTION: "crwdns3321:0%{DESCRIPTION}crwdne3321:0" event_reservation_DESCRIPTION: "crwdns3323:0%{DESCRIPTION}crwdne3323:0" + from_payment_schedule: "crwdns36355:0%{NUMBER}crwdnd36355:0%{TOTAL}crwdnd36355:0%{DATE}crwdnd36355:0%{SCHEDULE}crwdne36355:0" full_price_ticket: one: "crwdns3325:1crwdne3325:1" other: "crwdns3325:5%{count}crwdne3325:5" diff --git a/test/helpers/invoice_helper.rb b/test/helpers/invoice_helper.rb index ce7198d6c..4fb6941fe 100644 --- a/test/helpers/invoice_helper.rb +++ b/test/helpers/invoice_helper.rb @@ -31,7 +31,7 @@ module InvoiceHelper def generate_pdf(invoice) invoice_worker = InvoiceWorker.new - invoice_worker.perform(invoice.id, invoice&.user&.subscription&.expired_at) + invoice_worker.perform(invoice.id) end # Parse a line of text read from a PDF file and return the price included inside