mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-26 20:54:21 +01:00
(feat) generate invoices for missing references
This commit is contained in:
parent
227c6d1844
commit
3cff0d4c28
@ -13,7 +13,7 @@ class PaymentDocument < Footprintable
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update_reference
|
def update_reference
|
||||||
generate_reference
|
generate_reference if reference.blank?
|
||||||
save
|
save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,15 +33,10 @@ class Pdf::Invoice < Prawn::Document
|
|||||||
Rails.logger.error "Unable to decode invoice logo from base64: #{e}"
|
Rails.logger.error "Unable to decode invoice logo from base64: #{e}"
|
||||||
end
|
end
|
||||||
move_down 20
|
move_down 20
|
||||||
# the following line is a special comment to workaround RubyMine inspection problem
|
|
||||||
# noinspection RubyScope
|
|
||||||
font('Open-Sans', size: 10) do
|
font('Open-Sans', size: 10) do
|
||||||
# general information
|
# general information
|
||||||
if invoice.is_a?(Avoir)
|
text I18n.t(invoice.is_a?(Avoir) ? 'invoices.refund_invoice_reference' : 'invoices.invoice_reference',
|
||||||
text I18n.t('invoices.refund_invoice_reference', **{ REF: invoice.reference }), leading: 3
|
**{ REF: invoice.reference }), leading: 3
|
||||||
else
|
|
||||||
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')
|
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
|
if invoice.main_item&.object_type != WalletTransaction.name
|
||||||
text I18n.t('invoices.order_number', **{ NUMBER: invoice.order_number }), leading: 3
|
text I18n.t('invoices.order_number', **{ NUMBER: invoice.order_number }), leading: 3
|
||||||
|
@ -21,7 +21,7 @@ class Invoices::LabelService
|
|||||||
when 'OfferDay'
|
when 'OfferDay'
|
||||||
offer_day_label(invoice.main_item.object, username)
|
offer_day_label(invoice.main_item.object, username)
|
||||||
when 'Error'
|
when 'Error'
|
||||||
I18n.t('invoices.error_invoice')
|
invoice.main_item&.object_id&.zero? ? I18n.t('invoices.error_invoice') : invoice.main_item&.description
|
||||||
when 'StatisticProfilePrepaidPack'
|
when 'StatisticProfilePrepaidPack'
|
||||||
I18n.t('invoices.prepaid_pack')
|
I18n.t('invoices.prepaid_pack')
|
||||||
when 'OrderItem'
|
when 'OrderItem'
|
||||||
|
@ -22,20 +22,32 @@ class Invoices::NumberService
|
|||||||
saved_number[indices[0]..indices[1]]&.to_i
|
saved_number[indices[0]..indices[1]]&.to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
# Replace the number of the reference of the given document and return the new reference
|
# Search for any document matching the provided period and number
|
||||||
# @param document [PaymentDocument,NilClass]
|
# @param number [Integer] the number to search
|
||||||
|
# @param date [Time] the date to search around, when using periodicity != 'global'
|
||||||
# @param setting [String] 'invoice_reference' | 'invoice_order-nb'
|
# @param setting [String] 'invoice_reference' | 'invoice_order-nb'
|
||||||
# @return [String,NilClass]
|
# @param klass [Class] Invoice | Order | PaymentSchedule
|
||||||
def change_number(document, new_number, setting = 'invoice_reference')
|
# @return [PaymentDocument,NilClass]
|
||||||
|
def find_by_number(number, date: Time.current, setting: 'invoice_reference', klass: Invoice)
|
||||||
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
||||||
return nil if document.nil?
|
return nil if number.nil?
|
||||||
|
|
||||||
saved_number = setting == 'invoice_reference' ? document.reference : document.order_number
|
pattern = pattern(date, setting)
|
||||||
return nil if saved_number.nil?
|
pattern = pattern.gsub(/([SXR]\[[^\]]+\])+/, '%')
|
||||||
|
if pattern.match?(/n+/)
|
||||||
|
pattern = pattern.gsub(/n+(?![^\[]*\])/) do |match|
|
||||||
|
pad_and_truncate(number, match.to_s.length)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
start_idx = pattern.index(/y+|m+|d+/)
|
||||||
|
end_idx = pattern.rindex(/y+|m+|d+/)
|
||||||
|
pattern[start_idx..end_idx] = pad_and_truncate(number, end_idx - start_idx + 1)
|
||||||
|
end
|
||||||
|
pattern = PaymentDocumentService.send(:replace_date_pattern, pattern, date)
|
||||||
|
|
||||||
indices = number_indices(document, setting)
|
field = setting == 'invoice_reference' ? 'reference' : 'order_number'
|
||||||
saved_number[indices[0]..indices[1]] = pad_and_truncate(new_number, indices[1] - indices[0])
|
field = 'reference' if klass == Order
|
||||||
saved_number
|
klass.where("#{field} LIKE '#{pattern}'").first
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param document [PaymentDocument,NilClass]
|
# @param document [PaymentDocument,NilClass]
|
||||||
@ -45,7 +57,7 @@ class Invoices::NumberService
|
|||||||
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
||||||
return nil if document.nil?
|
return nil if document.nil?
|
||||||
|
|
||||||
pattern = pattern(document, setting)
|
pattern = pattern(document.created_at, setting)
|
||||||
pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern)
|
pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern)
|
||||||
|
|
||||||
return 'global' if pattern.match?(/n+/)
|
return 'global' if pattern.match?(/n+/)
|
||||||
@ -56,15 +68,15 @@ class Invoices::NumberService
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the pattern applicable to generate the number of the given invoice.
|
# Get the pattern applicable to generate the given number at the given date.
|
||||||
# @param document [PaymentDocument]
|
# @param date [Time]
|
||||||
# @param setting [String] 'invoice_reference' | 'invoice_order-nb'
|
# @param setting [String] 'invoice_reference' | 'invoice_order-nb'
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def pattern(document, setting = 'invoice_reference')
|
def pattern(date, setting = 'invoice_reference')
|
||||||
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
||||||
|
|
||||||
value = Setting.find_by(name: setting).value_at(document.created_at)
|
value = Setting.find_by(name: setting).value_at(date)
|
||||||
value || if document.created_at < Setting.find_by(name: setting).first_update
|
value || if date < Setting.find_by(name: setting).first_update
|
||||||
Setting.find_by(name: setting).first_value
|
Setting.find_by(name: setting).first_value
|
||||||
else
|
else
|
||||||
Setting.get(setting)
|
Setting.get(setting)
|
||||||
@ -89,7 +101,7 @@ class Invoices::NumberService
|
|||||||
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting)
|
||||||
return nil if document.nil?
|
return nil if document.nil?
|
||||||
|
|
||||||
pattern = pattern(document, setting)
|
pattern = pattern(document.created_at, setting)
|
||||||
pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern)
|
pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern)
|
||||||
start_idx = pattern.index(/n+|y+|m+|d+/)
|
start_idx = pattern.index(/n+|y+|m+|d+/)
|
||||||
end_idx = pattern.rindex(/n+|y+|m+|d+/)
|
end_idx = pattern.rindex(/n+|y+|m+|d+/)
|
||||||
|
@ -16,27 +16,17 @@ class Invoices::PaymentDetailsService
|
|||||||
build_avoir_details(invoice, total)
|
build_avoir_details(invoice, total)
|
||||||
else
|
else
|
||||||
# subtract the wallet amount for this invoice from the total
|
# subtract the wallet amount for this invoice from the total
|
||||||
if invoice.wallet_amount
|
wallet_amount = wallet_amount(invoice)
|
||||||
wallet_amount = invoice.wallet_amount / 100.00
|
total -= wallet_amount unless wallet_amount.nil?
|
||||||
total -= wallet_amount
|
return '' if wallet_amount.nil? && total.zero?
|
||||||
else
|
|
||||||
wallet_amount = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# payment method
|
# payment method
|
||||||
payment_verbose = if invoice.paid_by_card?
|
payment_verbose = payment_mean(invoice, total, wallet_amount)
|
||||||
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',
|
payment_verbose += " #{I18n.t('invoices.on_DATE_at_TIME',
|
||||||
**{ DATE: I18n.l(invoice.created_at.to_date),
|
**{ DATE: I18n.l(invoice.created_at.to_date),
|
||||||
TIME: I18n.l(invoice.created_at, format: :hour_minute) })}"
|
TIME: I18n.l(invoice.created_at, format: :hour_minute) })}"
|
||||||
if total.positive? || !invoice.wallet_amount
|
if total.positive? || wallet_amount.nil?
|
||||||
payment_verbose += " #{I18n.t('invoices.for_an_amount_of_AMOUNT', **{ AMOUNT: number_to_currency(total) })}"
|
payment_verbose += " #{I18n.t('invoices.for_an_amount_of_AMOUNT', **{ AMOUNT: number_to_currency(total) })}"
|
||||||
end
|
end
|
||||||
if invoice.wallet_amount
|
if invoice.wallet_amount
|
||||||
@ -53,6 +43,30 @@ class Invoices::PaymentDetailsService
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# @param invoice [Invoice]
|
||||||
|
# @return [Float,NilClass]
|
||||||
|
def wallet_amount(invoice)
|
||||||
|
return invoice.wallet_amount / 100.00 if invoice.wallet_amount
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param invoice [Invoice]
|
||||||
|
# @param total [Float]
|
||||||
|
# @param wallet_amount [Float,NilClass]
|
||||||
|
# @return [String]
|
||||||
|
def payment_mean(invoice, total, wallet_amount)
|
||||||
|
# if the invoice was 100% payed with the wallet ...
|
||||||
|
return I18n.t('invoices.settlement_by_wallet') if total.zero? && !wallet_amount.nil?
|
||||||
|
|
||||||
|
# else
|
||||||
|
if invoice.paid_by_card?
|
||||||
|
I18n.t('invoices.settlement_by_debit_card')
|
||||||
|
else
|
||||||
|
I18n.t('invoices.settlement_done_at_the_reception')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# @param invoice [Invoice]
|
# @param invoice [Invoice]
|
||||||
# @param total [Float]
|
# @param total [Float]
|
||||||
# @return [String]
|
# @return [String]
|
||||||
|
@ -7,7 +7,7 @@ class PaymentDocumentService
|
|||||||
# @param document [PaymentDocument]
|
# @param document [PaymentDocument]
|
||||||
# @param date [Time]
|
# @param date [Time]
|
||||||
def generate_reference(document, date: Time.current)
|
def generate_reference(document, date: Time.current)
|
||||||
pattern = Invoices::NumberService.pattern(document, 'invoice_reference')
|
pattern = Invoices::NumberService.pattern(document.created_at, 'invoice_reference')
|
||||||
|
|
||||||
reference = replace_document_number_pattern(pattern, document)
|
reference = replace_document_number_pattern(pattern, document)
|
||||||
reference = replace_date_pattern(reference, date)
|
reference = replace_date_pattern(reference, date)
|
||||||
@ -16,7 +16,7 @@ class PaymentDocumentService
|
|||||||
|
|
||||||
# @param document [PaymentDocument]
|
# @param document [PaymentDocument]
|
||||||
def generate_order_number(document)
|
def generate_order_number(document)
|
||||||
pattern = Invoices::NumberService.pattern(document, 'invoice_order-nb')
|
pattern = Invoices::NumberService.pattern(document.created_at, 'invoice_order-nb')
|
||||||
|
|
||||||
# global document number (nn..nn)
|
# global document number (nn..nn)
|
||||||
reference = pattern.gsub(/n+(?![^\[]*\])/) do |match|
|
reference = pattern.gsub(/n+(?![^\[]*\])/) do |match|
|
||||||
@ -27,6 +27,19 @@ class PaymentDocumentService
|
|||||||
replace_date_pattern(reference, document.created_at)
|
replace_date_pattern(reference, document.created_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generate a reference for the given document using the given document number
|
||||||
|
# @param number [Integer]
|
||||||
|
# @param document [PaymentDocument]
|
||||||
|
def generate_numbered_reference(number, document)
|
||||||
|
pattern = Invoices::NumberService.pattern(document.created_at, 'invoice_reference')
|
||||||
|
|
||||||
|
reference = pattern.gsub(/n+|y+|m+|d+(?![^\[]*\])/) do |match|
|
||||||
|
pad_and_truncate(number, match.to_s.length)
|
||||||
|
end
|
||||||
|
reference = replace_date_pattern(reference, document.created_at)
|
||||||
|
replace_document_type_pattern(document, reference)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Output the given integer with leading zeros. If the given value is longer than the given
|
# Output the given integer with leading zeros. If the given value is longer than the given
|
||||||
|
@ -102,6 +102,7 @@ en:
|
|||||||
training_reservation_DESCRIPTION: "Training reservation - %{DESCRIPTION}"
|
training_reservation_DESCRIPTION: "Training reservation - %{DESCRIPTION}"
|
||||||
event_reservation_DESCRIPTION: "Event reservation - %{DESCRIPTION}"
|
event_reservation_DESCRIPTION: "Event reservation - %{DESCRIPTION}"
|
||||||
from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}"
|
from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}"
|
||||||
|
null_invoice: "Invoice at nil, billing jump following a malfunction of the Fab Manager software"
|
||||||
full_price_ticket:
|
full_price_ticket:
|
||||||
one: "One full price ticket"
|
one: "One full price ticket"
|
||||||
other: "%{count} full price tickets"
|
other: "%{count} full price tickets"
|
||||||
|
@ -102,6 +102,7 @@ fr:
|
|||||||
training_reservation_DESCRIPTION: "Réservation Formation - %{DESCRIPTION}"
|
training_reservation_DESCRIPTION: "Réservation Formation - %{DESCRIPTION}"
|
||||||
event_reservation_DESCRIPTION: "Réservation Événement - %{DESCRIPTION}"
|
event_reservation_DESCRIPTION: "Réservation Événement - %{DESCRIPTION}"
|
||||||
from_payment_schedule: "Échéance %{NUMBER} sur %{TOTAL}, du %{DATE}. Échéancier de paiement %{SCHEDULE}"
|
from_payment_schedule: "Échéance %{NUMBER} sur %{TOTAL}, du %{DATE}. Échéancier de paiement %{SCHEDULE}"
|
||||||
|
null_invoice: 'Facture à néant, saut de facturation suite à un dysfonctionnement du logiciel Fab Manager'
|
||||||
full_price_ticket:
|
full_price_ticket:
|
||||||
one: "Une place plein tarif"
|
one: "Une place plein tarif"
|
||||||
other: "%{count} places plein tarif"
|
other: "%{count} places plein tarif"
|
||||||
|
@ -85,11 +85,11 @@ CREATE FUNCTION public.fill_search_vector_for_project() RETURNS trigger
|
|||||||
select string_agg(description, ' ') as content into step_description from project_steps where project_id = new.id;
|
select string_agg(description, ' ') as content into step_description from project_steps where project_id = new.id;
|
||||||
|
|
||||||
new.search_vector :=
|
new.search_vector :=
|
||||||
setweight(to_tsvector('pg_catalog.norwegian', unaccent(coalesce(new.name, ''))), 'A') ||
|
setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(new.name, ''))), 'A') ||
|
||||||
setweight(to_tsvector('pg_catalog.norwegian', unaccent(coalesce(new.tags, ''))), 'B') ||
|
setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(new.tags, ''))), 'B') ||
|
||||||
setweight(to_tsvector('pg_catalog.norwegian', unaccent(coalesce(new.description, ''))), 'D') ||
|
setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(new.description, ''))), 'D') ||
|
||||||
setweight(to_tsvector('pg_catalog.norwegian', unaccent(coalesce(step_title.title, ''))), 'C') ||
|
setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(step_title.title, ''))), 'C') ||
|
||||||
setweight(to_tsvector('pg_catalog.norwegian', unaccent(coalesce(step_description.content, ''))), 'D');
|
setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(step_description.content, ''))), 'D');
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
end
|
end
|
||||||
@ -115,8 +115,8 @@ SET default_tablespace = '';
|
|||||||
|
|
||||||
CREATE TABLE public.abuses (
|
CREATE TABLE public.abuses (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
signaled_type character varying,
|
|
||||||
signaled_id integer,
|
signaled_id integer,
|
||||||
|
signaled_type character varying,
|
||||||
first_name character varying,
|
first_name character varying,
|
||||||
last_name character varying,
|
last_name character varying,
|
||||||
email character varying,
|
email character varying,
|
||||||
@ -236,8 +236,8 @@ CREATE TABLE public.addresses (
|
|||||||
locality character varying,
|
locality character varying,
|
||||||
country character varying,
|
country character varying,
|
||||||
postal_code character varying,
|
postal_code character varying,
|
||||||
placeable_type character varying,
|
|
||||||
placeable_id integer,
|
placeable_id integer,
|
||||||
|
placeable_type character varying,
|
||||||
created_at timestamp without time zone,
|
created_at timestamp without time zone,
|
||||||
updated_at timestamp without time zone
|
updated_at timestamp without time zone
|
||||||
);
|
);
|
||||||
@ -346,8 +346,8 @@ CREATE TABLE public.ar_internal_metadata (
|
|||||||
|
|
||||||
CREATE TABLE public.assets (
|
CREATE TABLE public.assets (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
viewable_type character varying,
|
|
||||||
viewable_id integer,
|
viewable_id integer,
|
||||||
|
viewable_type character varying,
|
||||||
attachment character varying,
|
attachment character varying,
|
||||||
type character varying,
|
type character varying,
|
||||||
created_at timestamp without time zone,
|
created_at timestamp without time zone,
|
||||||
@ -965,8 +965,8 @@ ALTER SEQUENCE public.coupons_id_seq OWNED BY public.coupons.id;
|
|||||||
|
|
||||||
CREATE TABLE public.credits (
|
CREATE TABLE public.credits (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
creditable_type character varying,
|
|
||||||
creditable_id integer,
|
creditable_id integer,
|
||||||
|
creditable_type character varying,
|
||||||
plan_id integer,
|
plan_id integer,
|
||||||
hours integer,
|
hours integer,
|
||||||
created_at timestamp without time zone,
|
created_at timestamp without time zone,
|
||||||
@ -1762,15 +1762,15 @@ ALTER SEQUENCE public.notification_types_id_seq OWNED BY public.notification_typ
|
|||||||
CREATE TABLE public.notifications (
|
CREATE TABLE public.notifications (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
receiver_id integer,
|
receiver_id integer,
|
||||||
attached_object_type character varying,
|
|
||||||
attached_object_id integer,
|
attached_object_id integer,
|
||||||
|
attached_object_type character varying,
|
||||||
notification_type_id integer,
|
notification_type_id integer,
|
||||||
is_read boolean DEFAULT false,
|
is_read boolean DEFAULT false,
|
||||||
created_at timestamp without time zone,
|
created_at timestamp without time zone,
|
||||||
updated_at timestamp without time zone,
|
updated_at timestamp without time zone,
|
||||||
receiver_type character varying,
|
receiver_type character varying,
|
||||||
is_send boolean DEFAULT false,
|
is_send boolean DEFAULT false,
|
||||||
meta_data jsonb DEFAULT '"{}"'::jsonb
|
meta_data jsonb DEFAULT '{}'::jsonb
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -2498,8 +2498,8 @@ CREATE TABLE public.prices (
|
|||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
group_id integer,
|
group_id integer,
|
||||||
plan_id integer,
|
plan_id integer,
|
||||||
priceable_type character varying,
|
|
||||||
priceable_id integer,
|
priceable_id integer,
|
||||||
|
priceable_type character varying,
|
||||||
amount integer,
|
amount integer,
|
||||||
created_at timestamp without time zone NOT NULL,
|
created_at timestamp without time zone NOT NULL,
|
||||||
updated_at timestamp without time zone NOT NULL,
|
updated_at timestamp without time zone NOT NULL,
|
||||||
@ -2962,8 +2962,8 @@ CREATE TABLE public.reservations (
|
|||||||
message text,
|
message text,
|
||||||
created_at timestamp without time zone,
|
created_at timestamp without time zone,
|
||||||
updated_at timestamp without time zone,
|
updated_at timestamp without time zone,
|
||||||
reservable_type character varying,
|
|
||||||
reservable_id integer,
|
reservable_id integer,
|
||||||
|
reservable_type character varying,
|
||||||
nb_reserve_places integer,
|
nb_reserve_places integer,
|
||||||
statistic_profile_id integer
|
statistic_profile_id integer
|
||||||
);
|
);
|
||||||
@ -2995,8 +2995,8 @@ ALTER SEQUENCE public.reservations_id_seq OWNED BY public.reservations.id;
|
|||||||
CREATE TABLE public.roles (
|
CREATE TABLE public.roles (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
name character varying,
|
name character varying,
|
||||||
resource_type character varying,
|
|
||||||
resource_id integer,
|
resource_id integer,
|
||||||
|
resource_type character varying,
|
||||||
created_at timestamp without time zone,
|
created_at timestamp without time zone,
|
||||||
updated_at timestamp without time zone
|
updated_at timestamp without time zone
|
||||||
);
|
);
|
||||||
@ -5718,14 +5718,6 @@ ALTER TABLE ONLY public.roles
|
|||||||
ADD CONSTRAINT roles_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT roles_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.schema_migrations
|
|
||||||
ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: settings settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: settings settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -7385,6 +7377,21 @@ CREATE INDEX proof_of_identity_type_id_and_proof_of_identity_refusal_id ON publi
|
|||||||
CREATE UNIQUE INDEX unique_not_null_external_id ON public.invoicing_profiles USING btree (external_id) WHERE (external_id IS NOT NULL);
|
CREATE UNIQUE INDEX unique_not_null_external_id ON public.invoicing_profiles USING btree (external_id) WHERE (external_id IS NOT NULL);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX unique_schema_migrations ON public.schema_migrations USING btree (version);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: accounting_periods accounting_periods_del_protect; Type: RULE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE RULE accounting_periods_del_protect AS
|
||||||
|
ON DELETE TO public.accounting_periods DO INSTEAD NOTHING;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: accounting_periods accounting_periods_upd_protect; Type: RULE; Schema: public; Owner: -
|
-- Name: accounting_periods accounting_periods_upd_protect; Type: RULE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -8361,6 +8368,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||||||
('20140605125131'),
|
('20140605125131'),
|
||||||
('20140605142133'),
|
('20140605142133'),
|
||||||
('20140605151442'),
|
('20140605151442'),
|
||||||
|
('20140606133116'),
|
||||||
('20140609092700'),
|
('20140609092700'),
|
||||||
('20140609092827'),
|
('20140609092827'),
|
||||||
('20140610153123'),
|
('20140610153123'),
|
||||||
@ -8429,12 +8437,14 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||||||
('20150507075620'),
|
('20150507075620'),
|
||||||
('20150512123546'),
|
('20150512123546'),
|
||||||
('20150520132030'),
|
('20150520132030'),
|
||||||
|
('20150520133409'),
|
||||||
('20150526130729'),
|
('20150526130729'),
|
||||||
('20150527153312'),
|
('20150527153312'),
|
||||||
('20150529113555'),
|
('20150529113555'),
|
||||||
('20150601125944'),
|
('20150601125944'),
|
||||||
('20150603104502'),
|
('20150603104502'),
|
||||||
('20150603104658'),
|
('20150603104658'),
|
||||||
|
('20150603133050'),
|
||||||
('20150604081757'),
|
('20150604081757'),
|
||||||
('20150604131525'),
|
('20150604131525'),
|
||||||
('20150608142234'),
|
('20150608142234'),
|
||||||
@ -8516,6 +8526,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||||||
('20160905142700'),
|
('20160905142700'),
|
||||||
('20160906094739'),
|
('20160906094739'),
|
||||||
('20160906094847'),
|
('20160906094847'),
|
||||||
|
('20160906145713'),
|
||||||
('20160915105234'),
|
('20160915105234'),
|
||||||
('20161123104604'),
|
('20161123104604'),
|
||||||
('20170109085345'),
|
('20170109085345'),
|
||||||
|
@ -4,6 +4,7 @@ namespace :fablab do
|
|||||||
desc 'Fill the holes in the logical sequence of invoices references'
|
desc 'Fill the holes in the logical sequence of invoices references'
|
||||||
task fix_references: :environment do |_task, _args|
|
task fix_references: :environment do |_task, _args|
|
||||||
include ActionView::Helpers::NumberHelper
|
include ActionView::Helpers::NumberHelper
|
||||||
|
include DbHelper
|
||||||
|
|
||||||
user = User.adminsys || User.admins.first
|
user = User.adminsys || User.admins.first
|
||||||
|
|
||||||
@ -11,37 +12,53 @@ namespace :fablab do
|
|||||||
missing_references = {}
|
missing_references = {}
|
||||||
|
|
||||||
# browse invoices to list missing reference
|
# browse invoices to list missing reference
|
||||||
|
puts 'Computing missing references...'
|
||||||
not_closed(Invoice).order(created_at: :desc).each do |invoice|
|
not_closed(Invoice).order(created_at: :desc).each do |invoice|
|
||||||
number = Invoices::NumberService.number(invoice)
|
number = Invoices::NumberService.number(invoice)
|
||||||
next if number == 1
|
next if number == 1
|
||||||
|
|
||||||
previous = Invoices::NumberService.change_number(invoice, number - 1)
|
previous = Invoice.where('created_at < :date', date: db_time(invoice.created_at))
|
||||||
next unless Invoice.find_by(reference: previous).nil?
|
.order(created_at: :desc)
|
||||||
|
.limit(1)
|
||||||
|
.first
|
||||||
|
previous_number = Invoices::NumberService.number(previous)
|
||||||
|
next if previous_number.nil? || previous_number == number - 1
|
||||||
|
|
||||||
missing_references[invoice.created_at] ||= []
|
missing_references[invoice.created_at] ||= []
|
||||||
missing_references[invoice.created_at].push(previous)
|
|
||||||
|
# ignore numbers of already existing invoices
|
||||||
|
(previous_number + 1...number).to_a.each do |num|
|
||||||
|
next unless Invoices::NumberService.find_by_number(num, date: invoice.created_at).nil?
|
||||||
|
|
||||||
|
missing_references[invoice.created_at].push(num)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# create placeholder invoices for found missing references
|
# create placeholder invoices for found missing references
|
||||||
missing_references.each_pair do |date, references|
|
puts 'Creating missing invoices...'
|
||||||
references.reverse_each.with_index do |reference, index|
|
total = missing_references.values.filter(&:present?).flatten.count
|
||||||
Invoice.create!(
|
counter = 1
|
||||||
|
missing_references.each_pair do |date, numbers|
|
||||||
|
numbers.reverse_each.with_index do |number, index|
|
||||||
|
puts "#{counter} / #{total}"
|
||||||
|
invoice = Invoice.new(
|
||||||
total: 0,
|
total: 0,
|
||||||
invoicing_profile: user.invoicing_profile,
|
invoicing_profile: user.invoicing_profile,
|
||||||
statistic_profile: user.statistic_profile,
|
statistic_profile: user.statistic_profile,
|
||||||
operator_profile: user.invoicing_profile,
|
operator_profile: user.invoicing_profile,
|
||||||
payment_method: '',
|
payment_method: '',
|
||||||
reference: reference,
|
|
||||||
created_at: date - (index + 1).seconds,
|
created_at: date - (index + 1).seconds,
|
||||||
description: 'Facture à néant, saut de facturation suite à un dysfonctionnement du logiciel Fab Manager',
|
|
||||||
invoice_items_attributes: [{
|
invoice_items_attributes: [{
|
||||||
amount: 0,
|
amount: 0,
|
||||||
description: 'facture à zéro',
|
description: I18n.t('invoices.null_invoice'),
|
||||||
object_type: 'Error',
|
object_type: 'Error',
|
||||||
object_id: 1,
|
object_id: 1,
|
||||||
main: true
|
main: true
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
|
invoice.reference = PaymentDocumentService.generate_numbered_reference(number, invoice)
|
||||||
|
invoice.save!
|
||||||
|
counter += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -8,7 +8,9 @@ namespace :fablab do
|
|||||||
I18n.t('invoices.order_number', locale: 'en', **{ NUMBER: 'REPLACE' }).gsub('REPLACE', ''),
|
I18n.t('invoices.order_number', locale: 'en', **{ NUMBER: 'REPLACE' }).gsub('REPLACE', ''),
|
||||||
I18n.t('invoices.order_number', locale: 'fr', **{ NUMBER: 'REPLACE' }).gsub('REPLACE', '')
|
I18n.t('invoices.order_number', locale: 'fr', **{ NUMBER: 'REPLACE' }).gsub('REPLACE', '')
|
||||||
]
|
]
|
||||||
|
max_id = ActiveRecord::Base.connection.execute('SELECT max(id) as max_id FROM invoices').first['max_id']
|
||||||
Invoice.order(id: :asc).find_each do |invoice|
|
Invoice.order(id: :asc).find_each do |invoice|
|
||||||
|
puts "Processing: #{invoice.id} / #{max_id}"
|
||||||
next unless File.exist?(invoice.file)
|
next unless File.exist?(invoice.file)
|
||||||
|
|
||||||
found = false
|
found = false
|
||||||
@ -21,7 +23,7 @@ namespace :fablab do
|
|||||||
order_text.each do |label|
|
order_text.each do |label|
|
||||||
next unless line.include? label
|
next unless line.include? label
|
||||||
|
|
||||||
number = line.gsub(label, '').strip
|
number = line.gsub(label, '').gsub(/\s{5,}.+$/, '').strip
|
||||||
invoice.update(order_number: number)
|
invoice.update(order_number: number)
|
||||||
found = true
|
found = true
|
||||||
end
|
end
|
||||||
@ -46,5 +48,12 @@ namespace :fablab do
|
|||||||
item.invoice&.update(order_number: schedule.order_number)
|
item.invoice&.update(order_number: schedule.order_number)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Avoir.where(order_number: nil).order(id: :asc).find_each do |refund|
|
||||||
|
next if refund.invoice.nil?
|
||||||
|
|
||||||
|
# refunds are validated against their avoir_date for inclusion in closed periods, so we must bypass the validation
|
||||||
|
# (Invoices are validated on Time.current, so this was not necesseary above)
|
||||||
|
refund.update_attribute('order_number', refund.invoice.order_number) # rubocop:disable Rails/SkipsModelValidations
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -140,4 +140,9 @@ class Invoices::NumberServiceTest < ActiveSupport::TestCase
|
|||||||
periodicity = Invoices::NumberService.number_periodicity(invoice, 'invoice_order-nb')
|
periodicity = Invoices::NumberService.number_periodicity(invoice, 'invoice_order-nb')
|
||||||
assert_equal 'month', periodicity
|
assert_equal 'month', periodicity
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'find document by number' do
|
||||||
|
invoice = Invoices::NumberService.find_by_number(1, date: Time.zone.parse('2012-03-01'))
|
||||||
|
assert_equal Invoice.first, invoice
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user