easy_invoices 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1237c953b5e5dcaf5ec52540e91f75108721a3edf42e4f9164c62ed30b241261
4
+ data.tar.gz: 1e00a916870b26d22bfdbd71f142b8049b9653ac2724994888966e2317a7bda6
5
+ SHA512:
6
+ metadata.gz: cc29eb7d56132decae0300830974f20547cf0279f8969eaa6f4d536c65a5604d43dc5798fd18fc7210d0a59cfee5d99590e2a60005494a07164620572a457b09
7
+ data.tar.gz: 7cd65e6a48467048ad0597785b1476fbaca562257278ac901f677068ea059db819c9593bd36cc8c05a3807f3d1cf70a9ededc4dae2ed56faf8ec82a5602a581d
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ easy_invoices
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.5.1
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.4.1
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in easy_invoices.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,54 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ easy_invoices (0.1.0)
5
+ ru_propisju (~> 2.6, >= 2.6.0)
6
+ wicked_pdf (~> 2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (6.0.2.2)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 0.7, < 2)
14
+ minitest (~> 5.1)
15
+ tzinfo (~> 1.1)
16
+ zeitwerk (~> 2.2)
17
+ concurrent-ruby (1.1.6)
18
+ diff-lcs (1.3)
19
+ i18n (1.8.2)
20
+ concurrent-ruby (~> 1.0)
21
+ minitest (5.14.0)
22
+ rake (13.0.1)
23
+ rspec (3.9.0)
24
+ rspec-core (~> 3.9.0)
25
+ rspec-expectations (~> 3.9.0)
26
+ rspec-mocks (~> 3.9.0)
27
+ rspec-core (3.9.1)
28
+ rspec-support (~> 3.9.1)
29
+ rspec-expectations (3.9.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.9.0)
32
+ rspec-mocks (3.9.1)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.9.0)
35
+ rspec-support (3.9.2)
36
+ ru_propisju (2.6.0)
37
+ thread_safe (0.3.6)
38
+ tzinfo (1.2.6)
39
+ thread_safe (~> 0.1)
40
+ wicked_pdf (2.0.2)
41
+ activesupport
42
+ zeitwerk (2.3.0)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ bundler (~> 2.0)
49
+ easy_invoices!
50
+ rake (~> 13.0, >= 12.3.3)
51
+ rspec (~> 3.2)
52
+
53
+ BUNDLED WITH
54
+ 2.0.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Kairat Zhumaniyazov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # EasyInvoices
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/easy_invoices`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'easy_invoices'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install easy_invoices
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/easy_invoices.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "easy_invoices"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,31 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "easy_invoices/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "easy_invoices"
7
+ spec.version = EasyInvoices::VERSION
8
+ spec.authors = ["Kairat Zhumaniyazov"]
9
+ spec.email = ["k.zhumaniyazov@gmail.com"]
10
+
11
+ spec.summary = %q{Easy invoices in pdf}
12
+ spec.description = %q{Easy invoices in pdf}
13
+ spec.homepage = "https://github.com/kairat-zhumaniyazov"
14
+ spec.license = "MIT"
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_runtime_dependency "wicked_pdf", "~> 2.0"
26
+ spec.add_runtime_dependency "ru_propisju", "~> 2.6", ">= 2.6.0"
27
+
28
+ spec.add_development_dependency "bundler", "~> 2.0"
29
+ spec.add_development_dependency "rake", ">= 12.3.3", "~> 13.0"
30
+ spec.add_development_dependency "rspec", "~> 3.2"
31
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'generator'
2
+
3
+ class EasyInvoices::Act < EasyInvoices::Generator
4
+
5
+ DIR = %w'public system pdfs atcs'
6
+
7
+ FIELDS = %i'
8
+ title
9
+ execuror
10
+ customer
11
+ positions
12
+ execuror_position
13
+ execuror_name
14
+ customer_position
15
+ customer_name
16
+ '
17
+
18
+ end
@@ -0,0 +1,65 @@
1
+ module EasyInvoices
2
+ module Base
3
+
4
+ DIGIT_RUBLEJ = { always_show_fraction: true, fraction_formatter: '%d', integrals_delimiter: ' ' }
5
+
6
+ def generate_act(options = {})
7
+ generate_with(:act, options)
8
+ end
9
+
10
+ def generate_invoice(options = {})
11
+ generate_with(:invoice, options)
12
+ end
13
+
14
+ def generate_with(kind, options = {})
15
+ begin
16
+ check_easy_invoices_options(kind)
17
+ check_document_data_method_existing
18
+ generate_params_hash(kind, options)
19
+ calculate_act_total_sum
20
+ file = "EasyInvoices::#{kind.to_s.classify}".constantize.generate(@params_hash, options[:file_name])
21
+ options[:success_callback].call(file) if options.dig(:success_callback)
22
+ return { result: :success, file: file }
23
+ rescue => e
24
+ puts e.message
25
+ options[:error_callback].call(file) if options.dig(:error_callback)
26
+ return { result: :error, error_message: e.message }
27
+ end
28
+ end
29
+
30
+ protected
31
+
32
+ def check_easy_invoices_options(kind)
33
+ @options = self.class.easy_invoices_options
34
+ raise('EasyInvoices options not found') unless @options
35
+ @kinds = @options.dig(:kind)
36
+ raise('EasyInvoices document kind not found') unless @kinds
37
+ tmp_msg = "EasyInvoices document kinds not included #{kind}"
38
+ if @kinds.is_a?(Array)
39
+ raise(tmp_msg) unless @kinds.include?(kind)
40
+ else
41
+ raise(tmp_msg) unless @kinds == kind
42
+ end
43
+ true
44
+ end
45
+
46
+ def check_document_data_method_existing
47
+ raise('EasyInvoices document_data method not defined in model') unless respond_to?(:document_data, true)
48
+ end
49
+
50
+ def generate_params_hash(kind, options)
51
+ @params_hash = {
52
+ sings: self.class.easy_invoices_options.dig(:signs, kind),
53
+ with_signs: options.dig(:with_signs).nil? ? true : options[:with_signs]
54
+ }
55
+
56
+ "EasyInvoices::#{kind.to_s.classify}".constantize::FIELDS.each do |field|
57
+ @params_hash[field] = document_data(kind, field) rescue "Value for #{field} not found"
58
+ end
59
+ end
60
+
61
+ def calculate_act_total_sum
62
+ @params_hash[:total_sum] = @params_hash[:positions].map { |pos| pos[:cost] * pos[:amount] }.reduce(:+)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,63 @@
1
+ require 'wicked_pdf'
2
+ require 'ru_propisju'
3
+
4
+ class EasyInvoices::Generator
5
+
6
+ def self.generate(invoice_params, file_name)
7
+ self.new(invoice_params, file_name).process
8
+ end
9
+
10
+ def initialize(invoice_params, file_name)
11
+ @invoice_params = invoice_params
12
+ @file_name = file_name.nil? ? "#{SecureRandom.hex}.pdf" : "#{file_name}.pdf"
13
+ end
14
+
15
+ def process
16
+ check_dir
17
+
18
+ File.open(target_file, 'wb') do |file|
19
+ file << rendered_pdf
20
+ end
21
+
22
+ target_file
23
+ end
24
+
25
+ protected
26
+
27
+ def check_dir
28
+ FileUtils.mkdir_p(target_dir) unless File.directory?(target_dir)
29
+ end
30
+
31
+ def target_dir
32
+ Rails.root.join(*self.class::DIR)
33
+ end
34
+
35
+ def target_file
36
+ target_dir.join @file_name
37
+ end
38
+
39
+ def current_dir
40
+ File.expand_path(File.dirname(__FILE__))
41
+ end
42
+
43
+ def template_path
44
+ "#{current_dir}/templates/#{self.class.name.demodulize.downcase}"
45
+ end
46
+
47
+ def rendered_pdf
48
+ WickedPdf.config = {
49
+ 'no-background': false,
50
+ image: true
51
+ }
52
+ WickedPdf.new.pdf_from_string( rendered_view )
53
+ end
54
+
55
+ def rendered_view
56
+ ApplicationController.render(
57
+ file: template_path,
58
+ layout: false,
59
+ locals: @invoice_params
60
+ )
61
+ end
62
+
63
+ end
@@ -0,0 +1,17 @@
1
+ module EasyInvoices
2
+ module Includer
3
+
4
+ def can_generate_document options = {}
5
+ @easy_invoices_options = options
6
+
7
+ class_eval do
8
+ def self.easy_invoices_options
9
+ @easy_invoices_options
10
+ end
11
+ end
12
+
13
+ include EasyInvoices::Base
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ require 'wicked_pdf'
2
+ require 'ru_propisju'
3
+ require_relative 'generator'
4
+
5
+ class EasyInvoices::Invoice < EasyInvoices::Generator
6
+
7
+ DIR = %w'public system pdfs invoices'
8
+
9
+ FIELDS = %i'
10
+ title
11
+ supplier_requisites
12
+ bank_name
13
+ bank_bik
14
+ bank_city
15
+ bank_account
16
+ bank_inn
17
+ bank_kpp
18
+ bank_recipient_name
19
+ bank_recipient_account
20
+ buyer_requisiter
21
+ positions
22
+ payment_terms
23
+ director_name
24
+ buhgalter_name
25
+ '
26
+
27
+ end
@@ -0,0 +1,349 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 0;
11
+ font-family: sans-serif;
12
+ font-size: 14px;
13
+ text-align: justify;
14
+ }
15
+
16
+ .no-text-wrap {
17
+ white-space: nowrap;
18
+ }
19
+
20
+ .clearfix::after {
21
+ content: "";
22
+ display: table;
23
+ clear: both;
24
+ }
25
+
26
+ .text-center {
27
+ text-align: center;
28
+ }
29
+
30
+ .container {
31
+ width: 90%;
32
+ margin: 0 auto;
33
+ }
34
+
35
+ .header h1 {
36
+ font-size: 1.4em;
37
+ text-align: left;
38
+ }
39
+
40
+ .requistes table {
41
+ border-collapse:separate;
42
+ border-spacing: 0 1.2em;
43
+ }
44
+
45
+ .requistes td.title {
46
+ font-weight: bold;
47
+ vertical-align: top;
48
+ }
49
+
50
+ .requistes td.separator {
51
+ width: 20px;
52
+ }
53
+
54
+ .main table {
55
+ border-collapse: collapse;
56
+ margin-bottom: 30px;
57
+ }
58
+
59
+ .main table th {
60
+ white-space: nowrap;
61
+ padding: 3px 5px;
62
+ text-align: center;
63
+ }
64
+
65
+ .main th, .main td {
66
+ border: 1px solid black;
67
+ }
68
+
69
+ .main table td {
70
+ padding: 3px 5px;
71
+ }
72
+
73
+ .main table td.money {
74
+ padding: 3px 10px 3px 15px;
75
+ white-space: nowrap;
76
+ text-align: right;
77
+ }
78
+
79
+ .main table td.fantom {
80
+ border: 0;
81
+ }
82
+
83
+ .main .total .title, .main .nds .title {
84
+ text-align: right;
85
+ font-weight: bold;
86
+ }
87
+
88
+ .desc {
89
+ margin-bottom: 30px;
90
+ }
91
+
92
+ .sum-inwords {
93
+ margin-bottom: 30px;
94
+ }
95
+
96
+ .sum-inwords .title {
97
+ font-weight: bold;
98
+ float: left;
99
+ margin-right: 20px;
100
+ }
101
+
102
+ .sum-inwords .words {
103
+ text-decoration: underline;
104
+ }
105
+
106
+ .signatures-wrapper {
107
+ position: relative;
108
+ padding: 0 !important;
109
+ width: 100%;
110
+ }
111
+
112
+ .signatures {
113
+ margin-bottom: 30px;
114
+ width: 100%;
115
+ }
116
+
117
+ .signatures .title {
118
+ font-weight: bold;
119
+ margin-bottom: 20px;
120
+ }
121
+
122
+ .execuror {
123
+ width: 100%;
124
+ }
125
+ .customer {
126
+ width: 100%;
127
+ }
128
+
129
+ .signatures table {
130
+ width: 100%;
131
+ border-collapse: collapse;
132
+ }
133
+
134
+ .signatures .border-bot {
135
+ border-bottom: 1px solid #000;
136
+ }
137
+
138
+ .font-80 {
139
+ font-size: 80%;
140
+ }
141
+
142
+ table .text-top {
143
+ vertical-align: top;
144
+ }
145
+
146
+ .signatures .separator {
147
+ height: 30px;
148
+ }
149
+
150
+ .w-40 {
151
+ width: 40%;
152
+ }
153
+ </style>
154
+ <title><%= title %></title>
155
+ </head>
156
+ <body>
157
+
158
+ <div class="container">
159
+ <div class="header">
160
+ <h1>
161
+ <%= title %>
162
+ </h1>
163
+ </div>
164
+
165
+
166
+ <div class="requistes">
167
+ <table>
168
+ <tbody>
169
+
170
+ <tr>
171
+ <td class="title">Исполнитель:</td>
172
+ <td class="separator">&nbsp;</td>
173
+ <td>
174
+ <%= execuror %>
175
+ </td>
176
+ </tr>
177
+
178
+ <tr>
179
+ <td class="title">Заказчик:</td>
180
+ <td class="separator">&nbsp;</td>
181
+ <td>
182
+ <%= customer %>
183
+ </td>
184
+ </tr>
185
+
186
+ </tbody>
187
+ </table>
188
+ </div>
189
+
190
+
191
+ <div class="main">
192
+ <table>
193
+ <thead>
194
+ <th>№</th>
195
+ <th>Наименование товаров, работ, услуг</th>
196
+ <th>Кол-во</th>
197
+ <th>Ед. изм.</th>
198
+ <th>Цена</th>
199
+ <th>Всего</th>
200
+ </thead>
201
+
202
+ <tbody>
203
+
204
+ <% positions.each_with_index do |position, index| %>
205
+ <tr>
206
+ <td class="text-center"><%= index + 1 %></td>
207
+ <td><%= position[:name] %></td>
208
+ <td class="text-center"><%= position[:amount] %></td>
209
+ <td class="text-center"><%= position[:units] %></td>
210
+ <td class="text-center money">
211
+ <%= RuPropisju.delimited_number('%.2f' % position[:cost], ' ') %>
212
+ </td>
213
+ <td class="text-center money">
214
+ <%= RuPropisju.delimited_number('%.2f' % (position[:cost] * position[:amount]), ' ') %>
215
+ </td>
216
+ </tr>
217
+ <% end %>
218
+
219
+ <tr class="total">
220
+ <td class="fantom" colspan="4"></td>
221
+ <td class="title no-text-wrap">Итого:</td>
222
+ <td class="text-center money">
223
+ <%= RuPropisju.delimited_number('%.2f' % total_sum, ' ') %>
224
+ </td>
225
+ </tr>
226
+
227
+ <tr class="nds">
228
+ <td class="fantom" colspan="4"></td>
229
+ <td class="title no-text-wrap">В т.ч. НДС:</td>
230
+ <td class="text-center money">Без НДС</td>
231
+ </tr>
232
+
233
+ </tbody>
234
+ </table>
235
+
236
+ <div class="sum-inwords">
237
+ <div class="title">
238
+ Всего оказано услуг на сумму:
239
+ </div>
240
+
241
+ <div class="words">
242
+ <%= "#{RuPropisju.rublej(total_sum, :ru, EasyInvoices::Base::DIGIT_RUBLEJ).capitalize}. Без НДС" %>
243
+ </div>
244
+ </div>
245
+
246
+
247
+ <div class="desc">
248
+ Вышеперечисленные услуги выполнены полностью и в срок. Заказчик претензий по объему, качеству и срокам оказания услуг не имеет.
249
+ </div>
250
+ </div>
251
+
252
+
253
+ <div class="signatures-wrapper">
254
+ <table class="signatures">
255
+ <tr>
256
+ <td>
257
+ <div class="execuror">
258
+ <div class="title">Испольнитель</div>
259
+
260
+ <table>
261
+ <tr>
262
+ <td class="border-bot text-center" colspan="2">
263
+ <%= execuror_position %>
264
+ </td>
265
+ </tr>
266
+ <tr>
267
+ <td class="text-center font-80 text-top" colspan="2">
268
+ должность
269
+ </td>
270
+ </tr>
271
+
272
+ <tr class="separator">
273
+ <td colspan="2"></td>
274
+ </tr>
275
+
276
+ <tr>
277
+ <td class="border-bot"></td>
278
+ <td class="border-bot text-center">
279
+ <%= execuror_name %>
280
+ </td>
281
+ </tr>
282
+ <tr>
283
+ <td class="text-center font-80 text-top">подпись</td>
284
+ <td class="text-center font-80 text-top w-40">расшифровка подписи</td>
285
+ </tr>
286
+ </table>
287
+
288
+ </div>
289
+ </td>
290
+ <td style="width: 20px;">&nbsp;</td>
291
+ <td>
292
+ <div class="customer">
293
+ <div class="title">Заказчик</div>
294
+
295
+ <table>
296
+ <tr>
297
+ <td class="border-bot text-center" colspan="2">
298
+ <%= customer_position.present? ? customer_position : raw('&nbsp') %>
299
+ </td>
300
+ </tr>
301
+ <tr>
302
+ <td class="text-center font-80 text-top" colspan="2">должность</td>
303
+ </tr>
304
+
305
+ <tr class="separator">
306
+ <td colspan="2"></td>
307
+ </tr>
308
+
309
+ <tr>
310
+ <td class="border-bot">&nbsp;</td>
311
+ <td class="border-bot text-center">
312
+ <%= customer_name.present? ? customer_name : raw('&nbsp') %>
313
+ </td>
314
+ </tr>
315
+ <tr>
316
+ <td class="text-center font-80 text-top">подпись</td>
317
+ <td class="text-center font-80 text-top w-40">расшифровка подписи</td>
318
+ </tr>
319
+ </table>
320
+ </div>
321
+ </td>
322
+ </tr>
323
+ </table>
324
+
325
+ <% if with_signs && sings %>
326
+ <% sings.each_with_index do |sign, index| %>
327
+ <% size = EasyInvoices::BASE_SIGN_SIZE * sign[:scale] %>
328
+
329
+ <div class="faximile" id='sign_<%= index + 1 %>'
330
+ style='
331
+ position: absolute;
332
+ background-size: cover;
333
+ background-repeat: no-repeat;
334
+ width: <%= size %>px;
335
+ height: <%= size %>px;
336
+ top: <%= sign[:x] || 0 %>px;
337
+ left: <%= sign[:y] || 0 %>px;
338
+ background-color: <%= sign[:debug] ? '#dddddd' : '' %>;
339
+ background-image: url(<%= wicked_pdf_asset_base64("easy_invoices/#{sign[:file_name]}") %>);'>
340
+ </div>
341
+ <% end %>
342
+ <% end %>
343
+
344
+ </div>
345
+
346
+ </div>
347
+
348
+ </body>
349
+ </html>
@@ -0,0 +1,397 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 0;
11
+ font-family: sans-serif;
12
+ font-size: 14px;
13
+ text-align: justify;
14
+ }
15
+
16
+ .no-text-wrap {
17
+ white-space: nowrap;
18
+ }
19
+
20
+ .no-border {
21
+ border: 0 !important;
22
+ }
23
+
24
+ .text-center {
25
+ text-align: center;
26
+ }
27
+
28
+ .container {
29
+ width: 90%;
30
+ margin: 0 auto;
31
+ }
32
+
33
+ .requistes-table {
34
+ border-collapse: separate;
35
+ border-spacing: 0 1.2em;
36
+ }
37
+
38
+ .requistes-table td.title {
39
+ font-weight: bold;
40
+ vertical-align: top;
41
+ }
42
+
43
+ .requistes-table td.separator {
44
+ width: 20px;
45
+ }
46
+
47
+ .ert {
48
+ text-align: left;
49
+ border-collapse: collapse;
50
+ border-spacing: 0;
51
+ width: 100%;
52
+ }
53
+
54
+ .ert td {
55
+ vertical-align: top;
56
+ padding: 5px;
57
+ border: 1px solid #000000;
58
+ }
59
+
60
+ td.va-middle {
61
+ vertical-align: middle;
62
+ }
63
+
64
+ td.bbottom-0 {
65
+ border-bottom: 0;
66
+ }
67
+
68
+ td.btop-0 {
69
+ border-top: 0;
70
+ }
71
+
72
+ .ert-row-1, .ert-row-2, .ert-row-4 {
73
+ height: 70px;
74
+ }
75
+
76
+ .ert-row-3 {
77
+ height: 30px;
78
+ }
79
+
80
+ .ert-col-1 {
81
+ width: 60%;
82
+ }
83
+
84
+ .ert-col-2 {
85
+ width: 10%;
86
+ }
87
+
88
+ .ert-col-3 {
89
+ width: 30%;
90
+ }
91
+
92
+ .ert-col-flex {
93
+ height: 1px;
94
+ }
95
+
96
+ .ert-flex-wrapper {
97
+ display: flex;
98
+ justify-content: space-between;
99
+ flex-direction: column;
100
+ height: 100%;
101
+ }
102
+
103
+ .ert-desc {
104
+ font-size: .8em;
105
+ }
106
+
107
+ table.positions {
108
+ border-collapse: collapse;
109
+ margin-bottom: 20px;
110
+ }
111
+
112
+ table.positions th {
113
+ white-space: nowrap;
114
+ padding: 3px 5px;
115
+ text-align: center;
116
+ }
117
+
118
+ .positions th, .positions td {
119
+ border: 1px solid black;
120
+ }
121
+
122
+ table.positions td {
123
+ padding: 3px 5px;
124
+ }
125
+
126
+ table.positions td.money {
127
+ padding: 3px 10px 3px 15px;
128
+ white-space: nowrap;
129
+ text-align: right;
130
+ }
131
+
132
+ table.positions td.fantom {
133
+ border: 0;
134
+ }
135
+
136
+ .positions .total .title, .positions .nds .title {
137
+ text-align: right;
138
+ font-weight: bold;
139
+ }
140
+
141
+ .summary, .sum-in-words {
142
+ margin: 0;
143
+ }
144
+
145
+ .sum-in-words {
146
+ margin-bottom: 15px;
147
+ }
148
+
149
+ .terms-of-payment .title, .sum-in-words {
150
+ font-weight: bold;
151
+ }
152
+
153
+ .signatures-wrapper {
154
+ position: relative;
155
+ width: 100%;
156
+ }
157
+
158
+ .signatures {
159
+ width: 90%;
160
+ }
161
+
162
+ .signatures tr {
163
+ height: 50px;
164
+ }
165
+
166
+ .signatures td {
167
+ vertical-align: bottom;
168
+ }
169
+
170
+ .signatures .hr {
171
+ width: 30%;
172
+ vertical-align: bottom;
173
+ border-bottom: 1px solid #000000;
174
+ }
175
+
176
+ .signatures td.position {
177
+ vertical-align: bottom;
178
+ width: 80px;
179
+ }
180
+ </style>
181
+ <title><%= title %></title>
182
+ </head>
183
+ <body>
184
+ <div class="container">
185
+ <div class="header">
186
+ <h1>
187
+ <%= title %>
188
+ </h1>
189
+ </div>
190
+
191
+ <div class="requistes">
192
+ <table class="requistes-table">
193
+ <tbody>
194
+
195
+ <tr>
196
+ <td class="title">Поставщик:</td>
197
+ <td class="separator">&nbsp;</td>
198
+ <td>
199
+ <%= supplier_requisites %>
200
+ </td>
201
+ </tr>
202
+
203
+ </tbody>
204
+ </table>
205
+
206
+
207
+ <table class="ert" border="1">
208
+ <tr class="ert-row-1">
209
+ <td class="ert-col-1 bbottom-0" colspan="4">
210
+ <%= bank_name %>
211
+ </td>
212
+ <td class="ert-col-2">БИК</td>
213
+ <td class="ert-col-3">
214
+ <%= bank_bik %>
215
+ </td>
216
+ </tr>
217
+
218
+ <tr class="ert-row-2">
219
+ <td colspan="4" class="ert-col-flex btop-0">
220
+ <div class="ert-flex-wrapper">
221
+ <div>
222
+ <%= bank_city %>
223
+ </div>
224
+ <div class="ert-desc">
225
+ Банк получателя
226
+ </div>
227
+ </div>
228
+ </td>
229
+ <td>Сч. №</td>
230
+ <td>
231
+ <%= bank_account %>
232
+ </td>
233
+ </tr>
234
+
235
+ <tr class="ert-row-3">
236
+ <td class="text-center">ИНН</td>
237
+ <td class="text-center"><%= bank_inn %></td>
238
+ <td class="text-center">КПП</td>
239
+ <td class="text-center"><%= bank_kpp %></td>
240
+ <td class="bbottom-0"></td>
241
+ <td class="bbottom-0"></td>
242
+ </tr>
243
+
244
+ <tr class="ert-row-4">
245
+ <td colspan="4" class="ert-col-flex">
246
+ <div class="ert-flex-wrapper">
247
+ <div>
248
+ <%= bank_recipient_name %>
249
+ </div>
250
+ <div class="ert-desc">
251
+ Получатель
252
+ </div>
253
+ </div>
254
+ </td>
255
+ <td class="va-middle btop-0">Сч. №</td>
256
+ <td class="va-middle btop-0">
257
+ <%= bank_recipient_account %>
258
+ </td>
259
+ </tr>
260
+ </table>
261
+
262
+
263
+ <table class="requistes-table">
264
+ <tbody>
265
+
266
+ <tr>
267
+ <td class="title">Покупатель:</td>
268
+ <td class="separator">&nbsp;</td>
269
+ <td>
270
+ <%= buyer_requisiter %>
271
+ </td>
272
+ </tr>
273
+
274
+ </tbody>
275
+ </table>
276
+ </div>
277
+
278
+
279
+ <table class="positions">
280
+ <thead>
281
+ <th>№</th>
282
+ <th>Наименование товаров, работ, услуг</th>
283
+ <th>Кол-во</th>
284
+ <th>Ед. изм.</th>
285
+ <th>Цена</th>
286
+ <th>Всего</th>
287
+ </thead>
288
+
289
+ <tbody>
290
+ <% positions.each_with_index do |position, index| %>
291
+ <tr>
292
+ <td class="text-center"><%= index + 1 %></td>
293
+ <td><%= position[:name] %></td>
294
+ <td class="text-center"><%= position[:amount] %></td>
295
+ <td class="text-center"><%= position[:units] %></td>
296
+ <td class="text-center money">
297
+ <%= RuPropisju.delimited_number('%.2f' % position[:cost], ' ') %>
298
+ </td>
299
+ <td class="text-center money">
300
+ <%= RuPropisju.delimited_number('%.2f' % (position[:cost] * position[:amount]), ' ') %>
301
+ </td>
302
+ </tr>
303
+ <% end %>
304
+
305
+ <tr class="total">
306
+ <td class="fantom" colspan="3"></td>
307
+ <td class="title no-text-wrap no-border" colspan="2">Итого к оплате:</td>
308
+ <td class="text-center money">
309
+ <%= RuPropisju.delimited_number('%.2f' % total_sum, ' ') %>
310
+ </td>
311
+ </tr>
312
+
313
+ <tr class="nds">
314
+ <td class="fantom" colspan="3"></td>
315
+ <td class="title no-text-wrap no-border" colspan="2">Без налога (НДС)</td>
316
+ <td class="money"> - </td>
317
+ </tr>
318
+
319
+ </tbody>
320
+ </table>
321
+
322
+ <div class="sums">
323
+ <p class="summary">
324
+ <span>
325
+ Всего наименовании
326
+ </span>
327
+ <span><%= positions.size %></span>
328
+ <span>
329
+ на сумму
330
+ </span>
331
+ <span>
332
+ <%= RuPropisju.digit_rublej(total_sum, :ru, EasyInvoices::Base::DIGIT_RUBLEJ) %>
333
+ </span>
334
+ </p>
335
+ <p class="sum-in-words">
336
+ <%= RuPropisju.rublej(total_sum, :ru, EasyInvoices::Base::DIGIT_RUBLEJ).capitalize %>
337
+ </p>
338
+ </div>
339
+
340
+ <div class="terms-of-payment">
341
+ <span class="title">Условия оплаты: </span>
342
+ <span>
343
+ <%= payment_terms %>
344
+ </span>
345
+ </div>
346
+
347
+ <div class="signatures-wrapper">
348
+ <table class="signatures">
349
+ <tr>
350
+ <td class="position">
351
+ Директор
352
+ </td>
353
+ <td class="devider">&nbsp;</td>
354
+ <td class="hr"></td>
355
+ <td class="fio">
356
+ <span>(</span>
357
+ <%= director_name %>
358
+ <span>)</span>
359
+ </td>
360
+ </tr>
361
+ <tr>
362
+ <td class="position">
363
+ Бухгалтер
364
+ </td>
365
+ <td class="devider">&nbsp;</td>
366
+ <td class="hr">&nbsp;</td>
367
+ <td class="fio">
368
+ <span>(</span>
369
+ <%= buhgalter_name %>
370
+ <span>)</span>
371
+ </td>
372
+ </tr>
373
+ </table>
374
+
375
+ <% if with_signs && sings %>
376
+ <% sings.each_with_index do |sign, index| %>
377
+ <% size = EasyInvoices::BASE_SIGN_SIZE * sign[:scale] %>
378
+
379
+ <div class="faximile" id='sign_<%= index + 1 %>'
380
+ style='
381
+ position: absolute;
382
+ background-size: cover;
383
+ background-repeat: no-repeat;
384
+ width: <%= size %>px;
385
+ height: <%= size %>px;
386
+ top: <%= sign[:x] || 0 %>px;
387
+ left: <%= sign[:y] || 0 %>px;
388
+ background-color: <%= sign[:debug] ? '#dddddd' : '' %>;
389
+ background-image: url(<%= wicked_pdf_asset_base64("easy_invoices/#{sign[:file_name]}") %>);'>
390
+ </div>
391
+ <% end %>
392
+ <% end %>
393
+ </div>
394
+ </div>
395
+
396
+ </body>
397
+ </html>
@@ -0,0 +1,3 @@
1
+ module EasyInvoices
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,15 @@
1
+ require "easy_invoices/base"
2
+ require "easy_invoices/version"
3
+ require "easy_invoices/includer"
4
+ require "easy_invoices/act"
5
+ require "easy_invoices/invoice"
6
+
7
+ module EasyInvoices
8
+ class Error < StandardError; end
9
+
10
+ BASE_SIGN_SIZE = 200
11
+
12
+ ActiveSupport.on_load(:active_record) do
13
+ extend EasyInvoices::Includer
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: easy_invoices
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kairat Zhumaniyazov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-03-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: wicked_pdf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ru_propisju
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.6.0
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '2.6'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.6.0
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.6'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 12.3.3
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '13.0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 12.3.3
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '13.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.2'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '3.2'
95
+ description: Easy invoices in pdf
96
+ email:
97
+ - k.zhumaniyazov@gmail.com
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - ".gitignore"
103
+ - ".rspec"
104
+ - ".ruby-gemset"
105
+ - ".ruby-version"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - easy_invoices.gemspec
115
+ - lib/easy_invoices.rb
116
+ - lib/easy_invoices/act.rb
117
+ - lib/easy_invoices/base.rb
118
+ - lib/easy_invoices/generator.rb
119
+ - lib/easy_invoices/includer.rb
120
+ - lib/easy_invoices/invoice.rb
121
+ - lib/easy_invoices/templates/act.html.erb
122
+ - lib/easy_invoices/templates/invoice.html.erb
123
+ - lib/easy_invoices/version.rb
124
+ homepage: https://github.com/kairat-zhumaniyazov
125
+ licenses:
126
+ - MIT
127
+ metadata: {}
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubyforge_project:
144
+ rubygems_version: 2.7.9
145
+ signing_key:
146
+ specification_version: 4
147
+ summary: Easy invoices in pdf
148
+ test_files: []