solidus_invoice 0.1.0
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 +15 -0
- data/.rspec +1 -0
- data/.rubocop.yml +250 -0
- data/.rvmrc +1 -0
- data/.travis.yml +18 -0
- data/Gemfile +10 -0
- data/MIT-LICENSE +20 -0
- data/README.md +38 -0
- data/Rakefile +32 -0
- data/app/assets/javascripts/spree/backend/solidus_invoice.js +2 -0
- data/app/assets/javascripts/spree/frontend/solidus_invoice.js +2 -0
- data/app/assets/stylesheets/spree/backend/solidus_invoice.scss +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_invoice.css +4 -0
- data/app/jobs/application_job.rb +9 -0
- data/app/jobs/solidus_invoice/daily_summary_job.rb +32 -0
- data/app/jobs/solidus_invoice/invoice_job.rb +22 -0
- data/app/models/concerns/solidus_invoice/line_item_concern.rb +11 -0
- data/app/models/concerns/solidus_invoice/order_concern.rb +44 -0
- data/app/models/concerns/solidus_invoice/shipment_concern.rb +11 -0
- data/app/models/concerns/solidus_invoice/store_concern.rb +11 -0
- data/app/models/spree.rb +7 -0
- data/app/models/spree/invoice.rb +61 -0
- data/app/models/spree/invoice_serial.rb +9 -0
- data/app/overrides/spree/line_item_override.rb +5 -0
- data/app/overrides/spree/order_override.rb +5 -0
- data/app/overrides/spree/shipment_override.rb +5 -0
- data/app/overrides/spree/store_override.rb +5 -0
- data/bin/rails +9 -0
- data/bin/test +7 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20191107042751_create_spree_invoices.rb +14 -0
- data/db/migrate/20191115204118_create_spree_invoice_serials.rb +13 -0
- data/db/migrate/20191205205004_add_tax_uid_to_spree_addresses.rb +7 -0
- data/db/migrate/20191223173229_add_preferences_to_spree_invoices.rb +7 -0
- data/lib/generators/solidus_invoice/install/install_generator.rb +22 -0
- data/lib/solidus_invoice.rb +4 -0
- data/lib/solidus_invoice/engine.rb +22 -0
- data/lib/solidus_invoice/errors/invalid_serial_error.rb +6 -0
- data/lib/solidus_invoice/factories.rb +34 -0
- data/lib/solidus_invoice/railtie.rb +6 -0
- data/lib/solidus_invoice/version.rb +5 -0
- data/lib/tasks/solidus_invoice_tasks.rake +5 -0
- data/solidus_invoice.gemspec +37 -0
- data/spec/jobs/solidus_invoice/daily_summary_job_spec.rb +24 -0
- data/spec/jobs/solidus_invoice/invoice_job_spec.rb +76 -0
- data/spec/models/spree/address_spec.rb +11 -0
- data/spec/models/spree/invoice_serial_spec.rb +16 -0
- data/spec/models/spree/invoice_spec.rb +55 -0
- data/spec/models/spree/line_item_spec.rb +37 -0
- data/spec/models/spree/order_spec.rb +31 -0
- data/spec/models/spree/shipment_spec.rb +26 -0
- data/spec/models/spree/store_spec.rb +9 -0
- data/spec/spec_helper.rb +98 -0
- metadata +320 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sunat_invoice'
|
4
|
+
|
5
|
+
class SolidusInvoice::InvoiceJob < ApplicationJob
|
6
|
+
queue_as :default
|
7
|
+
|
8
|
+
def perform(*args)
|
9
|
+
opts = args[0]
|
10
|
+
invoice = Spree::Invoice.find(opts[:invoice_id])
|
11
|
+
env = opts[:env]
|
12
|
+
|
13
|
+
sunat_invoice = invoice.build_sunat_invoice
|
14
|
+
|
15
|
+
if invoice.doc_type == '01'
|
16
|
+
# send to SUNAT
|
17
|
+
client = SunatInvoice::InvoiceClient.new(env)
|
18
|
+
response = client.dispatch(sunat_invoice)
|
19
|
+
invoice.update(communicated: true) if response.success?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'solidus_invoice/errors/invalid_serial_error'
|
4
|
+
|
5
|
+
module SolidusInvoice
|
6
|
+
module OrderConcern
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
has_many :invoices
|
11
|
+
after_save :generate_invoice
|
12
|
+
|
13
|
+
def generate_invoice
|
14
|
+
return unless can_generate_invoice?
|
15
|
+
|
16
|
+
doc_type = bill_address.tax_uid? ? '01' : '03'
|
17
|
+
doc_number = next_correlative(doc_type, store.id)
|
18
|
+
|
19
|
+
# generate Spree::Invoice
|
20
|
+
invoices.create(invoice_serial: get_serial(doc_type, store),
|
21
|
+
doc_number: doc_number,
|
22
|
+
order: self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def can_generate_invoice?
|
26
|
+
completed? && paid?
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_serial(doc_type, store = Spree::Store.default)
|
30
|
+
store.invoice_serials.find_by(doc_type: doc_type)
|
31
|
+
end
|
32
|
+
|
33
|
+
# given a store and document type get next posible correlative
|
34
|
+
def next_correlative(doc_type, store_id = Spree::Store.default.id)
|
35
|
+
store = Spree::Store.includes(invoice_serials: :invoices).find(store_id)
|
36
|
+
serial = get_serial(doc_type, store)
|
37
|
+
raise SolidusInvoice::InvalidSerialError unless serial
|
38
|
+
|
39
|
+
current = serial&.invoices&.order(doc_number: :desc)&.first&.doc_number || 0
|
40
|
+
current + 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/app/models/spree.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sunat_invoice'
|
4
|
+
|
5
|
+
class Spree::Invoice < Spree::Base
|
6
|
+
validates :doc_number, presence: true
|
7
|
+
|
8
|
+
belongs_to :order
|
9
|
+
belongs_to :invoice_serial
|
10
|
+
|
11
|
+
delegate :doc_type, :serial, to: :invoice_serial
|
12
|
+
|
13
|
+
preference :sunat_attributes, :hash
|
14
|
+
|
15
|
+
def sunat_attributes
|
16
|
+
attrs = (preferred_sunat_attributes || {}).dup
|
17
|
+
provider = SunatInvoice::Provider.new(attrs[:provider] || {})
|
18
|
+
attrs[:provider] = provider
|
19
|
+
attrs
|
20
|
+
end
|
21
|
+
|
22
|
+
# return a `SunatInvoice::Invoice`
|
23
|
+
def build_sunat_invoice
|
24
|
+
# generate SunatInvoice::Invoice
|
25
|
+
sunat_invoice = SunatInvoice::Invoice.new(sunat_attributes)
|
26
|
+
|
27
|
+
# add invoice lines from line_items
|
28
|
+
order.line_items.map do |line_item|
|
29
|
+
add_sunat_line(sunat_invoice, line_item)
|
30
|
+
end
|
31
|
+
|
32
|
+
# add invoice lines from shipment
|
33
|
+
order.shipments.map do |shipment|
|
34
|
+
next unless shipment.amount.positive?
|
35
|
+
|
36
|
+
add_sunat_line(sunat_invoice, shipment)
|
37
|
+
end
|
38
|
+
|
39
|
+
# store xml
|
40
|
+
store_xml(sunat_invoice.xml) if respond_to?(:store_xml)
|
41
|
+
|
42
|
+
sunat_invoice
|
43
|
+
end
|
44
|
+
|
45
|
+
# add a new `SunatInvoice::Item` to the given sunat invoice
|
46
|
+
# sunat_invoice => `SunatInvoice::Invoice` instance to add lines
|
47
|
+
# resource => an order's line_item or shipment
|
48
|
+
def add_sunat_line(sunat_invoice, resource)
|
49
|
+
# TODO: handle items with taxes different than vat
|
50
|
+
tax_amount = resource.adjustments.tax.sum(:amount)
|
51
|
+
tax = SunatInvoice::Tax.new(amount: tax_amount, tax_type: :igv)
|
52
|
+
quantity = resource.respond_to?(:quantity) ? resource.quantity : 1
|
53
|
+
item_attrs = {
|
54
|
+
quantity: quantity,
|
55
|
+
price: resource.price_excluding_vat,
|
56
|
+
price_code: '01',
|
57
|
+
taxes: [tax]
|
58
|
+
}
|
59
|
+
sunat_invoice.lines << SunatInvoice::Item.new(item_attrs)
|
60
|
+
end
|
61
|
+
end
|
data/bin/rails
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
4
|
+
|
5
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
6
|
+
ENGINE_PATH = File.expand_path('../../lib/solidus_invoice/engine', __FILE__)
|
7
|
+
|
8
|
+
require 'rails/all'
|
9
|
+
require 'rails/engine/commands'
|
data/bin/test
ADDED
data/config/routes.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateSpreeInvoices < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :spree_invoices do |t|
|
6
|
+
t.integer :doc_number
|
7
|
+
t.integer :order_id
|
8
|
+
t.integer :invoice_serial_id
|
9
|
+
t.boolean :communicated, default: false
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateSpreeInvoiceSerials < ActiveRecord::Migration[6.0]
|
4
|
+
def change
|
5
|
+
create_table :spree_invoice_serials do |t|
|
6
|
+
t.string :serial
|
7
|
+
t.integer :store_id
|
8
|
+
t.string :doc_type
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusInvoice
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
class_option :auto_run_migrations, type: :boolean, default: false
|
7
|
+
|
8
|
+
def add_migrations
|
9
|
+
run 'bundle exec rake railties:install:migrations FROM=solidus_invoice'
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_migrations
|
13
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
|
14
|
+
if run_migrations
|
15
|
+
run 'bundle exec rake db:migrate'
|
16
|
+
else
|
17
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusInvoice
|
4
|
+
class Engine < Rails::Engine
|
5
|
+
require 'spree/core'
|
6
|
+
isolate_namespace Spree
|
7
|
+
engine_name 'solidus_invoice'
|
8
|
+
|
9
|
+
# use rspec for tests
|
10
|
+
config.generators do |g|
|
11
|
+
g.test_framework :rspec
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.activate
|
15
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/overrides/**/*_override*.rb')) do |c|
|
16
|
+
require_dependency(c)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
config.to_prepare(&method(:activate).to_proc)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
FactoryBot.define do
|
4
|
+
factory :invoice, class: 'Spree::Invoice' do
|
5
|
+
doc_number { rand(450) }
|
6
|
+
order
|
7
|
+
invoice_serial
|
8
|
+
|
9
|
+
factory :invoice_with_serial do
|
10
|
+
before(:create) do |invoice|
|
11
|
+
store = create(:store)
|
12
|
+
invoice.invoice_serial { create(:invoice_serial, store: store) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
factory :invoice_serial, class: 'Spree::InvoiceSerial' do
|
18
|
+
store
|
19
|
+
doc_type { '03' }
|
20
|
+
serial { 'B023' }
|
21
|
+
end
|
22
|
+
|
23
|
+
factory :provider, class: 'SunatInvoice::Provider' do
|
24
|
+
signature_id { 'signatureST' }
|
25
|
+
signature_location_id { 'signQWI3' }
|
26
|
+
ruc { '20100454523' }
|
27
|
+
name { 'MY BUSINESS' }
|
28
|
+
end
|
29
|
+
|
30
|
+
factory :customer, class: 'SunatInvoice::Customer' do
|
31
|
+
ruc { '20293028401' }
|
32
|
+
name { 'SOME BUSINESS' }
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$:.push File.expand_path('lib', __dir__)
|
4
|
+
require 'solidus_invoice/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'solidus_invoice'
|
8
|
+
s.version = SolidusInvoice::VERSION
|
9
|
+
s.summary = 'generate invoice documents for solidus orders'
|
10
|
+
s.description = s.summary
|
11
|
+
s.license = 'MIT'
|
12
|
+
|
13
|
+
s.author = 'César Carruitero'
|
14
|
+
s.email = 'ccarruitero@protonmail.com'
|
15
|
+
s.homepage = 'https://github.com/ccarruitero/solidus_invoice'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
|
20
|
+
s.add_dependency 'solidus_core'
|
21
|
+
s.add_dependency 'solidus_support'
|
22
|
+
s.add_dependency 'sunat_invoice'
|
23
|
+
|
24
|
+
s.add_development_dependency 'capybara'
|
25
|
+
s.add_development_dependency 'database_cleaner'
|
26
|
+
s.add_development_dependency 'factory_bot'
|
27
|
+
s.add_development_dependency 'ffaker'
|
28
|
+
s.add_development_dependency 'mysql2'
|
29
|
+
s.add_development_dependency 'pg'
|
30
|
+
s.add_development_dependency 'pry'
|
31
|
+
s.add_development_dependency 'rspec-rails'
|
32
|
+
s.add_development_dependency 'rubocop'
|
33
|
+
s.add_development_dependency 'sass-rails'
|
34
|
+
s.add_development_dependency 'shoulda-matchers'
|
35
|
+
s.add_development_dependency 'simplecov'
|
36
|
+
s.add_development_dependency 'sqlite3'
|
37
|
+
end
|