Skip to content
This repository has been archived by the owner on Apr 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #13 from arsley/implement-invoice
Browse files Browse the repository at this point in the history
Feature/implmemt invoice 🚧
  • Loading branch information
arsley committed Apr 4, 2020
2 parents bb5a939 + 22dec22 commit 333ab79
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
working_times (0.6.0)
working_times (0.7.0)
activesupport (~> 5)
thor (~> 0.20.0)

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/arsley/working_times?style=flat-square)
[![Gem](https://img.shields.io/gem/v/working_times?style=flat-square)](https://rubygems.org/gems/working_times)
![GitHub](https://img.shields.io/github/license/arsley/working_times?style=flat-square)
![Travis (.com) branch](https://img.shields.io/travis/com/arsley/working_times/master?style=flat-square)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/arsley/working_times/Ruby?label=Ruby&style=flat-square)

Store your working(worked) time simply.
It's just record woking timestamp on specific file.
Expand Down Expand Up @@ -141,7 +141,7 @@ $ bundle exec rake
Check behavior without installation.

```
$ bundle exec exe/wt
$ bundle exec wt
```

## Contributing
Expand Down
1 change: 1 addition & 0 deletions lib/working_times.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
require 'working_times/config'
require 'working_times/state'
require 'working_times/record'
require 'working_times/invoice'
require 'working_times/cli'
23 changes: 22 additions & 1 deletion lib/working_times/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def init(workon, term = 'default', company = '')
end

FileUtils.mkdir_p(File.join(workon, 'terms'))
FileUtils.mkdir_p(File.join(workon, 'invoices'))
initialize_wtconf(workon, term, company)
end

Expand Down Expand Up @@ -57,6 +58,21 @@ def rest(duration)
Record.new(timestamp: DateTime.now, duration: duration).rest
end

option :build, type: :boolean, aliases: ['-b']
desc 'invoice', 'Create invoice for current term by TeX template. It will build pdf if option is set'
def invoice
Invoice.new.tap do |invoice|
invoice.generate
invoice.build if options[:build]
end
puts "Invoice created to #{path_invoice_current_term}."
end

desc 'version', 'Show version of working_times'
def version
puts 'version: ' + VERSION
end

private

def initialize_wtconf(workon, term, company)
Expand All @@ -65,7 +81,12 @@ def initialize_wtconf(workon, term, company)
File.write(File.join(data_dir, 'wtconf.json'), <<~WTCONF)
{
"term": "#{term}",
"company": "#{company}"
"invoice": {
"company": "#{company}",
"template": "",
"salaryPerHour": 0,
"taxRate": 0.0
}
}
WTCONF
end
Expand Down
16 changes: 16 additions & 0 deletions lib/working_times/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ def current_company
wtconf['company']
end

def invoice_dir
File.join(data_dir, 'invoices')
end

def invoice_info
wtconf['invoice']
end

def dir_invoice_current_term
File.join(invoice_dir, current_term)
end

def path_invoice_current_term
File.join(dir_invoice_current_term, "#{current_term}.tex")
end

def wtconf
JSON.parse(File.read(path_wtconf))
end
Expand Down
2 changes: 1 addition & 1 deletion lib/working_times/constants.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module WorkingTimes
VERSION = '0.6.0'.freeze
VERSION = '0.7.0'.freeze

START_MSG = [
'Have a nice work!',
Expand Down
133 changes: 133 additions & 0 deletions lib/working_times/invoice.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
module WorkingTimes
# Class about creating invoice
# This class is designed to build data_dir/invoices/current_term/invoice.tex
# from data_dir/invoices/template.tex
class Invoice
include Config
attr_reader :path_template, :salary_per_hour, :tax_rate, :company

WDAYS = %w[ ].freeze
Date::DATE_FORMATS[:jp_date] = '%m月%d日'
Time::DATE_FORMATS[:only_hm] = '%H:%M'

# path_template : String
# salary_per_hour : Integer
# tax_rate : Float
# company : String
def initialize
h_invoice_info = invoice_info

@path_template = h_invoice_info['template']
@salary_per_hour = h_invoice_info['salaryPerHour']
@tax_rate = h_invoice_info['taxRate']
@company = h_invoice_info['company']
end

def generate
create_dir_invoice_current_term
makeup_worktable
generate_invoice_from_template
end

def build
puts 'Currently, it is not available to build pdf with latexmk.'
puts 'Wait for new version!'
end

private

def create_dir_invoice_current_term
FileUtils.mkdir_p(dir_invoice_current_term)
end

def makeup_worktable
@worktable = [
'\hline',
'日付 & 曜日 & 内容 & 出勤 & 退勤 & 休憩 & 労働時間 \\\\ \hline\hline'
]
@allworktime_on_sec = 0.0
working_times = CSV.open(path_current_term, headers: true)
row = working_times.first
date_itr = beginning_of_month(row['started_at'])
date_itr.upto(date_itr.end_of_month) do |date|
if row.nil?
@worktable << format_worktable_row(date)
elsif same_day?(row['started_at'], date.rfc3339)
worktime = calculate_worktime(row['started_at'], row['finished_at'], row['rest_sec'])
@allworktime_on_sec += worktime
@worktable <<
format_worktable_row(date, row['comment'], row['started_at'], row['finished_at'], row['rest_sec'], worktime)
row = working_times.readline
else
@worktable << format_worktable_row(date)
end
end
end

def generate_invoice_from_template
template = File.readlines(path_template)
File.open(path_invoice_current_term, 'w') do |f|
template.each do |t|
t.gsub!(/##COMPANY##/, company)
t.gsub!(/##WORKTIME##/, parse_second_to_hh_str(@allworktime_on_sec))
t.gsub!(/##ACTUALWORKTIME##/, parse_second_to_hm_str(@allworktime_on_sec))
t.gsub!(/##SALARYPERHOUR##/, salary_per_hour.to_s)
t.gsub!(/##SALARY##/, salary.to_s)
t.gsub!(/##TAXRATE##/, "#{(tax_rate * 100).to_i}\\%")
t.gsub!(/##TAX##/, tax.to_s)
t.gsub!(/##SALARYWITHTAX##/, (salary + tax).to_s)
# on gsub, '\' means 'replace sub string'.
# so we should use block if work as expected
t.gsub!(/##WORKTABLE##/) { @worktable.join("\n") }

f.write(t)
end
end
end

def beginning_of_month(rfc3339)
Date.parse(rfc3339).beginning_of_month
end

def same_day?(one_rfc3339, another_rfc3339)
Date.parse(one_rfc3339) == Date.parse(another_rfc3339)
end

def calculate_worktime(st_rfc3339, fi_rfc3339, rest_sec)
Time.parse(fi_rfc3339) - Time.parse(st_rfc3339) - rest_sec.to_i
end

# date : Date
# comment : String
# started_at, finished_at : String (RFC3339)
# rest, worktime : Integer
def format_worktable_row(date, comment = nil, started_at = nil, finished_at = nil, rest = nil, worktime = nil)
"#{date.to_s(:jp_date)} & " \
"#{WDAYS[date.wday]} & " \
"#{comment || '-'} & " \
"#{started_at.nil? ? '-' : Time.parse(started_at).to_s(:only_hm)} & " \
"#{finished_at.nil? ? '-' : Time.parse(finished_at).to_s(:only_hm)} & " \
"#{rest.nil? ? '-' : parse_second_to_hm_str(rest.to_i)} & " \
"#{worktime.nil? ? '-' : parse_second_to_hm_str(worktime)} \\\\ \\hline"
end

def parse_second_to_hm_str(second)
h = (second / 3600).to_i
m = second - (3600 * h)
"#{h.to_i}:#{m.to_i.to_s.rjust(2, '0')}"
end

def parse_second_to_hh_str(second)
(second / 3600).to_i.to_s
end

# calculate with 'hour' only
def salary
@salary ||= @allworktime_on_sec.to_i / 3600 * salary_per_hour
end

def tax
@tax ||= (salary * tax_rate).to_i
end
end
end
14 changes: 14 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,23 @@
c.syntax = :expect
end

# disable STDERR, STDOUT during examples run when pry is not loaded
original_stderr = $stderr
original_stdout = $stdout

config.before(:all) do
# act tmp/ as current directory
FileUtils.cd(TMP_DIR)

unless respond_to? :pry
$stderr = File.open(File::NULL, 'w')
$stdout = File.open(File::NULL, 'w')
end
end

config.after(:all) do
$stderr = original_stderr
$stdout = original_stdout
end
end

Expand Down
47 changes: 36 additions & 11 deletions spec/working_times/cli/init_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@
let(:term) { 'test_term_1st' }
let(:company) { 'test_company' }

after do
FileUtils.cd('../')
FileUtils.rm_rf(workon)
end

context 'when call with workon' do
before do
WorkingTimes::CLI.new.init(workon)
FileUtils.cd(workon)
end

it 'creates directory' do
after do
FileUtils.cd('../')
expect(Dir.exist?(workon)).to be_truthy
FileUtils.rm_rf(workon)
end

it 'creates directory' do
expect(Dir.exist?('../' + workon)).to be_truthy
end

it 'creates wtconf.json' do
Expand All @@ -27,12 +26,28 @@
expect(Dir.exist?(term_dir)).to be_truthy
end

it 'creates invoices/' do
expect(File.exist?(invoice_dir)).to be_truthy
end

it 'includes default term in wtconf.json' do
expect(wtconf['term']).to eq('default')
end

it 'includes company as a blank in wtconf.json' do
expect(wtconf['company']).to eq('')
it 'includes invoice.company as a blank in wtconf.json' do
expect(wtconf['invoice']['company']).to eq('')
end

it 'includes invoice.template as a blank in wtconf.json' do
expect(wtconf['invoice']['template']).to eq('')
end

it 'includes invoice.salaryPerHour as 0 in wtconf.json' do
expect(wtconf['invoice']['salaryPerHour']).to eq(0)
end

it 'includes invoice.taxRate as 0.0 in wtconf.json' do
expect(wtconf['invoice']['taxRate']).to eq(0.0)
end
end

Expand All @@ -42,6 +57,11 @@
FileUtils.cd(workon)
end

after do
FileUtils.cd('../')
FileUtils.rm_rf(workon)
end

it 'includes specified term in wtconf.json' do
expect(wtconf['term']).to eq(term)
end
Expand All @@ -53,8 +73,13 @@
FileUtils.cd(workon)
end

it 'includes specified company in wtconf.json' do
expect(wtconf['company']).to eq(company)
after do
FileUtils.cd('../')
FileUtils.rm_rf(workon)
end

it 'includes specified invoice.company in wtconf.json' do
expect(wtconf['invoice']['company']).to eq(company)
end
end
end

0 comments on commit 333ab79

Please sign in to comment.