seisan 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +103 -0
- data/Rakefile +1 -0
- data/example/.gitignore +1 -0
- data/example/Gemfile +9 -0
- data/example/Rakefile +1 -0
- data/example/config.yaml +2 -0
- data/example/data/2013/07/20130704-sato.yaml +10 -0
- data/example/data/2013/07/20130705-shimada.yaml +10 -0
- data/lib/seisan.rb +24 -0
- data/lib/seisan/base_renderer.rb +18 -0
- data/lib/seisan/expense_renderer.rb +51 -0
- data/lib/seisan/header_renderer.rb +20 -0
- data/lib/seisan/report.rb +59 -0
- data/lib/seisan/task.rb +58 -0
- data/lib/seisan/version.rb +3 -0
- data/seisan.gemspec +26 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8dce330302998b4960917a287e0dc1a1bc6f206b
|
4
|
+
data.tar.gz: d458a54c3f25fb1a1f0d48e5c1b48db35264667f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 490afd74bb1a7071d58585b3d1a186bea9528b14518a6fab803d40a170b0443c696cfe5e104bcdc73cb600de025e5fdaf701cb71ee6c6460a753564884c52b54
|
7
|
+
data.tar.gz: 671ae0e0ceab39a778c7249754816809af42ee82127f9138af24109f42924cf13c4aaa2e66c36c7e1485b488a3e3b8a7234593656e2f0554c65c7c3196bae4cd
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Enishi Tech Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# Seisan
|
2
|
+
|
3
|
+
Seisan solution for small team.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
You need a few steps to setup seisan data repository. `example` directory in `enishitech/seisan` will be a good reference for you.
|
8
|
+
|
9
|
+
Put `Gemfile`:
|
10
|
+
|
11
|
+
```
|
12
|
+
source 'https://rubygems.org'
|
13
|
+
|
14
|
+
gem 'seisan'
|
15
|
+
```
|
16
|
+
|
17
|
+
Run bundler:
|
18
|
+
|
19
|
+
```shell
|
20
|
+
% bundle
|
21
|
+
```
|
22
|
+
|
23
|
+
Put `Rakefile`:
|
24
|
+
|
25
|
+
```
|
26
|
+
require 'seisan/task'
|
27
|
+
```
|
28
|
+
Create `data` directory to store data.
|
29
|
+
|
30
|
+
```shell
|
31
|
+
% mkdir data
|
32
|
+
```
|
33
|
+
|
34
|
+
OK, now everything is set up. Run
|
35
|
+
|
36
|
+
```shell
|
37
|
+
% bundle exec rake seisan TARGET=2013/07
|
38
|
+
```
|
39
|
+
|
40
|
+
Then you will have an empty monthly report (because you have no record in seisan data) at `output/2013-07.xlsx`.
|
41
|
+
|
42
|
+
You may want to add `output` directory to `.gitignore`:
|
43
|
+
|
44
|
+
```shell
|
45
|
+
% cat .gitignore
|
46
|
+
/output
|
47
|
+
```
|
48
|
+
|
49
|
+
## Usage
|
50
|
+
|
51
|
+
Given you record seisan data in the following format:
|
52
|
+
|
53
|
+
```
|
54
|
+
applicant: 佐藤
|
55
|
+
expense:
|
56
|
+
- date: 2013-6-24
|
57
|
+
amount: 105
|
58
|
+
remarks: 電池代
|
59
|
+
|
60
|
+
- date: 2013-7-4
|
61
|
+
amount: 2080
|
62
|
+
remarks: JR代
|
63
|
+
```
|
64
|
+
|
65
|
+
And you file seisan data as git repository like this:
|
66
|
+
|
67
|
+
```
|
68
|
+
% tree
|
69
|
+
data
|
70
|
+
└── 2013
|
71
|
+
├── ...
|
72
|
+
├── 07
|
73
|
+
│ ├── 20130709-shidara.yaml
|
74
|
+
│ ├── 20130711-sato.yaml
|
75
|
+
│ ├── 20130712-sato.yaml
|
76
|
+
│ ├── 20130717-shidara.yaml
|
77
|
+
│ └── 20130719-shimada.yaml
|
78
|
+
└── 08
|
79
|
+
├── 20130802-sato.yaml
|
80
|
+
├── 20130802-sekiya.yaml
|
81
|
+
├── 20130803-shidara.yaml
|
82
|
+
└── 08-shidara.yaml
|
83
|
+
```
|
84
|
+
|
85
|
+
Put `Rakefile` to your seisan data repository,
|
86
|
+
|
87
|
+
Then you can generate seisan report.
|
88
|
+
|
89
|
+
```shell
|
90
|
+
% bundle exec rake seisan TARGET=2013/07
|
91
|
+
```
|
92
|
+
|
93
|
+
## Contributing
|
94
|
+
|
95
|
+
1. Fork it
|
96
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
97
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
98
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
99
|
+
5. Create new Pull Request
|
100
|
+
|
101
|
+
-----
|
102
|
+
|
103
|
+
© 2013 Enishi Tech Inc.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/example/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
output
|
data/example/Gemfile
ADDED
data/example/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'seisan/task'
|
data/example/config.yaml
ADDED
data/lib/seisan.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'seisan/version'
|
2
|
+
require 'seisan/report'
|
3
|
+
require 'seisan/base_renderer'
|
4
|
+
require 'seisan/header_renderer'
|
5
|
+
require 'seisan/expense_renderer'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
module Seisan
|
9
|
+
def self.logger
|
10
|
+
@@logger ||= initialize_default_logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.logger=(logger)
|
14
|
+
@@logger = logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.initialize_default_logger
|
18
|
+
logger = Logger.new(STDOUT)
|
19
|
+
logger.formatter = proc{|severity, datetime, progname, message|
|
20
|
+
"#{message}\n"
|
21
|
+
}
|
22
|
+
logger
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Seisan
|
2
|
+
class BaseRenderer
|
3
|
+
def initialize(requests, sheet, font, config)
|
4
|
+
@requests = requests
|
5
|
+
@sheet = sheet
|
6
|
+
@font = font
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def requests
|
11
|
+
@requests
|
12
|
+
end
|
13
|
+
|
14
|
+
def row(columns=[])
|
15
|
+
@sheet.add_row columns, :style => @font
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'seisan/base_renderer'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Seisan
|
5
|
+
class ExpenseRenderer < BaseRenderer
|
6
|
+
def render
|
7
|
+
row ['立替払サマリー']
|
8
|
+
row summary_headings
|
9
|
+
summary.each do |person, amount|
|
10
|
+
row [person, amount]
|
11
|
+
end
|
12
|
+
row
|
13
|
+
|
14
|
+
row ['立替払明細']
|
15
|
+
row headings
|
16
|
+
lines.each do |line|
|
17
|
+
row line
|
18
|
+
end
|
19
|
+
row
|
20
|
+
|
21
|
+
Seisan.logger.info 'Processed %d expenses' % lines.size
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def summary_headings
|
26
|
+
%w(氏名 金額)
|
27
|
+
end
|
28
|
+
|
29
|
+
def summary
|
30
|
+
summary = Hash.new(0)
|
31
|
+
requests.each do |entry|
|
32
|
+
summary[entry['applicant']] += entry['expense'].inject(0){|r, e| r += e['amount'].to_i }
|
33
|
+
end
|
34
|
+
summary
|
35
|
+
end
|
36
|
+
|
37
|
+
def headings
|
38
|
+
%w(日付 立替者 金額 摘要 備考)
|
39
|
+
end
|
40
|
+
|
41
|
+
def lines
|
42
|
+
lines = []
|
43
|
+
requests.each do |entry|
|
44
|
+
entry['expense'].each do |expense|
|
45
|
+
lines << [expense['date'].to_s, entry['applicant'], expense['amount'], expense['remarks'], expense['notes']]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
lines.sort_by {|line| [Date.parse(line[0]), line[1]] }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'seisan/base_renderer'
|
2
|
+
|
3
|
+
module Seisan
|
4
|
+
class HeaderRenderer < BaseRenderer
|
5
|
+
def render
|
6
|
+
row ["#{organization_name} 精算シート #{target_name}"]
|
7
|
+
row ['作成時刻', Time.now.strftime('%Y-%m-%d %X')]
|
8
|
+
row
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def target_name
|
13
|
+
@config['target']
|
14
|
+
end
|
15
|
+
|
16
|
+
def organization_name
|
17
|
+
@config['organization'] ? @config['organization']['name'] : ''
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'axlsx'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'seisan/header_renderer'
|
4
|
+
require 'seisan/expense_renderer'
|
5
|
+
|
6
|
+
module Seisan
|
7
|
+
class Report
|
8
|
+
DEFAULT_RENDERERS = [
|
9
|
+
Seisan::HeaderRenderer,
|
10
|
+
Seisan::ExpenseRenderer
|
11
|
+
]
|
12
|
+
@@renderers = DEFAULT_RENDERERS
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def renderer_chain(&block)
|
16
|
+
@@renderers = []
|
17
|
+
block.call(self) if block
|
18
|
+
end
|
19
|
+
|
20
|
+
def add(renderer)
|
21
|
+
@@renderers << renderer
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(requests, config)
|
26
|
+
@requests = requests
|
27
|
+
@config = config
|
28
|
+
end
|
29
|
+
|
30
|
+
def export(dest_path)
|
31
|
+
prepare_sheet
|
32
|
+
|
33
|
+
renderers.each do |renderer|
|
34
|
+
renderer.render
|
35
|
+
end
|
36
|
+
|
37
|
+
write_to_file(dest_path)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def renderers
|
42
|
+
@@renderers.map {|r| r.new(@requests, @sheet, @font, @config) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def prepare_sheet
|
46
|
+
@package = Axlsx::Package.new
|
47
|
+
@workbook = @package.workbook
|
48
|
+
@package.use_shared_strings = true
|
49
|
+
@font = @workbook.styles.add_style :font_name => 'MS Pゴシック'
|
50
|
+
@sheet = @workbook.add_worksheet(:name => '精算シート')
|
51
|
+
end
|
52
|
+
|
53
|
+
def write_to_file(dest_path)
|
54
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
55
|
+
@package.serialize(dest_path)
|
56
|
+
Seisan.logger.info 'Wrote to %s' % dest_path
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/seisan/task.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'seisan'
|
3
|
+
require 'gimlet'
|
4
|
+
|
5
|
+
module Seisan
|
6
|
+
class Task
|
7
|
+
include Rake::DSL if defined? Rake::DSL
|
8
|
+
def self.install_tasks
|
9
|
+
new.install
|
10
|
+
end
|
11
|
+
|
12
|
+
def install
|
13
|
+
desc "Generate seisan report"
|
14
|
+
task :seisan do
|
15
|
+
src_dir, dest_dir = 'data', 'output'
|
16
|
+
config = user_config.merge('target' => ENV['TARGET'])
|
17
|
+
report(src_dir, dest_dir, config)
|
18
|
+
end
|
19
|
+
task :default => :seisan
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def report(src_dir, dest_dir, config)
|
24
|
+
if config['target'].nil?
|
25
|
+
Seisan.logger.error "You must specify the 'TARGET'.\nExample:\n % bundle exec rake TARGET=2013/07"
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
Seisan.logger.info 'Processing %s ...' % config['target']
|
30
|
+
requests = load_seisan_requests(src_dir, config['target'])
|
31
|
+
Seisan.logger.info 'Loaded %d files' % requests.size
|
32
|
+
report = Seisan::Report.new(requests, config)
|
33
|
+
|
34
|
+
dest_path = File.join(dest_dir, '%s.xlsx' % convert_target_to_file_name(config['target']))
|
35
|
+
report.export(dest_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def user_config
|
39
|
+
Gimlet::DataStore.new('config.yaml').to_h
|
40
|
+
rescue Gimlet::DataStore::SourceNotFound
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
|
44
|
+
def load_seisan_requests(src_dir, target)
|
45
|
+
source = Gimlet::DataStore.new(File.join(src_dir, target))
|
46
|
+
source.to_h.values
|
47
|
+
rescue Gimlet::DataStore::SourceNotFound
|
48
|
+
[]
|
49
|
+
end
|
50
|
+
|
51
|
+
def convert_target_to_file_name(target)
|
52
|
+
target.gsub('/', '-')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Install tasks
|
58
|
+
Seisan::Task.install_tasks
|
data/seisan.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'seisan/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "seisan"
|
8
|
+
spec.version = Seisan::VERSION
|
9
|
+
spec.authors = ["SHIMADA Koji"]
|
10
|
+
spec.email = ["koji.shimada@enishi-tech.com"]
|
11
|
+
spec.description = %q{seisan solution for small team}
|
12
|
+
spec.summary = %q{seisan solution for small team}
|
13
|
+
spec.homepage = "https://github.com/enishitech/seisan"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "axlsx", "~> 2.0.1"
|
22
|
+
spec.add_runtime_dependency "gimlet", "~> 0.0.3"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: seisan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- SHIMADA Koji
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: axlsx
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: gimlet
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.0.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: seisan solution for small team
|
70
|
+
email:
|
71
|
+
- koji.shimada@enishi-tech.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- example/.gitignore
|
82
|
+
- example/Gemfile
|
83
|
+
- example/Rakefile
|
84
|
+
- example/config.yaml
|
85
|
+
- example/data/2013/07/20130704-sato.yaml
|
86
|
+
- example/data/2013/07/20130705-shimada.yaml
|
87
|
+
- lib/seisan.rb
|
88
|
+
- lib/seisan/base_renderer.rb
|
89
|
+
- lib/seisan/expense_renderer.rb
|
90
|
+
- lib/seisan/header_renderer.rb
|
91
|
+
- lib/seisan/report.rb
|
92
|
+
- lib/seisan/task.rb
|
93
|
+
- lib/seisan/version.rb
|
94
|
+
- seisan.gemspec
|
95
|
+
homepage: https://github.com/enishitech/seisan
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.0.6
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: seisan solution for small team
|
119
|
+
test_files: []
|
120
|
+
has_rdoc:
|