-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor and improve invoices #1013
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More general note: This is not a refactoring. There are changes to both the external interface (rake task) and database schema.
end_time = params[:q][:due_date_lteq].try(:to_date) | ||
params[:q][:due_date_lteq] = end_time.try(:end_of_day) | ||
end_time = params[:q][:due_date_lteq] | ||
params[:q][:due_date_lteq] = end_time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this without the additonal methods, how is it different than:
a = 1
b = a
a = b # can be skipped
The rescue on lines 67-69 also seems weird now, the only error you might see is NoMethodError
when q
hash is Nil
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I postponed refactoring of that part of legacy code. There are some other things I don't understand as well.
db/structure.sql
Outdated
@@ -1052,7 +1052,8 @@ CREATE TABLE public.invoices ( | |||
cancelled_at timestamp without time zone, | |||
total numeric(10,2) NOT NULL, | |||
in_directo boolean DEFAULT false, | |||
buyer_vat_no character varying | |||
buyer_vat_no character varying, | |||
date date |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this is the right choice.
You need to know that it means the date the invoice was issued, and not due date, and it conflicts with SQL DATE
keyword.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. Did I make some mistake somewhere so that you mentioned due date? :)
I agree that DATE
itself is a reserved keyword, but in what way and what exactly conflicts?
I didn't notice any obstacles using it. Even if you need to use plain SQL, you just need to quote it.
Invoice has date so date
seems like a natural, self-explanatory name of a column.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that DATE itself is a reserved keyword, but in what way and what exactly conflicts?
It is a reserved keyword in all 3 recent SQL standards, which makes it generally not portable. In Oracle you cannot query such a column without escaping its name, it raises a parser exception.
I didn't notice any obstacles using it. Even if you need to use plain SQL, you just need to quote it.
That is precisely one of the reasons why you should avoid doing it. Quoted values are case sensitive, making them prone to bugs caused by typos and key rollovers.
create table dates(DATE DATE NOT NULL, ISSUE_DATE DATE NOT NULL);
select * from dates;
+--------+--------------+
| date | issue_date |
|--------+--------------|
+--------+--------------+
SELECT "Date" from dates;
column "Date" does not exist
LINE 1: SELECT "Date" from dates
^
HINT: Perhaps you meant to reference the column "dates.date".
SELECT ISSUE_Date from dates;
+--------------+
| issue_date |
|--------------|
+--------------+
SELECT 0
Invoice has date so date seems like a natural, self-explanatory name of a column.
It has 3 dates to be exact: the date when it was created, the date when it was sent to the customer and the date when it is due. Because of that, just date is not the best choice IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a contrived problem. We don't use Oracle. Very unlikely we will migrate to it in the visible future. Even if we need to, and plain SQL is needed, it's possible to either quote it or change the name to something else.
I still don't get the point... An invoice can have date
, due_date
, sent_date
(or date_sent
). What's the problem here?
Invoice date is quite standard terminology:
https://www.google.ee/search?q=invoice+date&rlz=1C1CHBF_enEE802EE802&source=lnms&tbm=isch&sa=X&ved=0ahUKEwiwg929l5DeAhXBZCwKHeCSBcUQ_AUIDigB&biw=1280&bih=584
https://en.wikipedia.org/wiki/Invoice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean it should be named issue_date
because simply date
is ambiguous or what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is what I mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, at least now I understand the point. However, I still see date
as a better fit (it is short and concise). I bet nobody will ask you to clarify, if you say just "Invoice date".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@artur-beljajev please fix the reserved date keyword issue. You always fight against ambiguity so it is hard to understand why all of the sudden its OK even if it is error prone and raises specific problems as @maciej-szlosarczyk described.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a problem using date
, which is a standard term for invoice.
https://www.google.ee/search?hl=en&as_q=&as_epq=invoice+date&as_oq=&as_eq=due&as_nlo=&as_nhi=&lr=&cr=&as_qdr=all&as_sitesearch=&as_occt=any&safe=images&as_filetype=&as_rights=
Omniva uses the same term: https://media.voog.com/0000/0042/1620/files/Estonian_e-invoice_description_ver1.2_eng.pdf
Our estonian_e_invoice
gem also sticks to it.
I find invoice.date
clearer and shorter. 99.9% of time we will use application layer (i.e. call invoice.date
), instead of manually building queries (in which case you will need to quote it). I don't find invoice.date
ambiguous.
Please elaborate, what problem it introduces in our case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another possible solution is to use alias_attribute :date, :issue_date
in Invoice
model, and rename database column invoices.date
to invoices.issue_date
.
end | ||
end | ||
|
||
puts "Invoice processed: #{processed_invoice_count}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor typo: Invoices processed
, plural
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
9ea1cf5
to
7d0a36f
Compare
It depends what you mean by external. The main point is that this PR does not (should not) affect any functional behavior (and UI). |
218546f
to
97bebeb
Compare
has merge conflicts with master |
88f061c
to
7f464ab
Compare
It appears that the change to start using reserved keyword date is still in effect here. So this change is postponed until the conflict is resolved. Wil come back to this after auction center release. |
056570c
to
106f5e2
Compare
@vohmar Is there anything preventing this PR from being merged with master? Invoice date issue has been fixed. |
106f5e2
to
706854b
Compare
6e85f37
to
72ce9d7
Compare
79c7501
to
b051ee6
Compare
- `runner 'Invoice.cancel_overdue_invoices'` in `schedule.rb` is changed to `rake 'invoices:cancel_overdue'`. - `invoices.payment_term` database column is removed and its value is hardcoded in UI. - `invoices.paid_at` is removed as unused - `invoices.due_date` column's type is now `date`. - `Invoice#invoice_items` renamed to `Invoice#items` and `Invoice` interface to get a list of items is unified. - Default date format in UI. - Default translations are used. - Tests improved. - Specs converted to tests and removed along with factories. - Database structure improved.
b051ee6
to
f9c6a8e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff.
2 small suggestions that might simplify operating on dates, but nothing earth-shattering.
due_date: (Time.zone.now.to_date + Setting.days_to_keep_invoices_active.days).end_of_day, | ||
payment_term: 'prepayment', | ||
issue_date: Time.zone.today, | ||
due_date: (Time.zone.now + Setting.days_to_keep_invoices_active.days).to_date, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Time.zone.today + Setting.days_to_keep_invoices_active
produces the same result, and does not convert between TimeWithZone and Date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was like this before. I will refactor it in a separate branch.
30.days | ||
end | ||
|
||
def self.delay |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess by renaming this to delay_in_days
we might get rid of operations on duration and treat them as integers, as does Date
.
def self.default_delay_in_days
30
end
def self.delay_in_days
Setting.days_to_keep_overdue_invoices_active || default_delay
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point was to just to avoid using _days
suffix and to introduce an abstraction (a delay). It allows to keep it in any units, be it a second, minute or year.
The rationale is that you postpone invoice cancellation for some period (after invoice due date). Delaying it for some period (a delay) sounds fine for me. Delaying it for 5
(an integer) does not.
cannot test automatic invoice cancellation and days_to_keep_overdue_invoices_active setting on staging. The error:
|
@vohmar See changelog in the description. |
@ratM1n Why we test against Ruby 2.4.0, whereas I understand there are no API changes between them, but I would still run exactly the same version on every deployment. Updating it should be just a matter of running |
Changes highlights:
runner 'Invoice.cancel_overdue_invoices'
inschedule.rb
is changed torake 'invoices:cancel_overdue'
.invoices.payment_term
database column is removed and its value is hardcoded in UI.invoices.paid_at
is removed as unused (@ratM1n reported zero rows with any value in prod as of 2019-03-11)invoices.due_date
column's type is nowdate
.Invoice#invoice_items
renamed toInvoice#items
andInvoice
interface to get a list of items is unified.Deployment:
rake data_migrations:populate_invoice_issue_date
should be run afterrake db:migrate
. This task populatesinvoices.issue_date
column with the date frominvoices.created_at
.All invoices should be valid for a data migration to be able to run. @ratM1n Reported zero invalid invoices on prod on 2018-10-18, but it may change. To get a list of them run
bundle exec rails c
and insert the following: https://gist.github.com/artur-beljajev/c3303eb3b39dcedf4a721548d0f3e6b7Verify:
days_to_keep_overdue_invoices_active
setting in Admin portal