sunat_invoice 0.0.1 → 0.0.3
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 +4 -4
- data/Gemfile +1 -0
- data/README.mkd +1 -25
- data/lib/sunat_invoice/client.rb +3 -6
- data/lib/sunat_invoice/clients/consult_client.rb +17 -0
- data/lib/sunat_invoice/clients/invoice_client.rb +11 -3
- data/lib/sunat_invoice/configuration.rb +1 -1
- data/lib/sunat_invoice/credit_note.rb +59 -0
- data/lib/sunat_invoice/credit_note_line.rb +15 -0
- data/lib/sunat_invoice/customer.rb +1 -0
- data/lib/sunat_invoice/daily_summary.rb +46 -0
- data/lib/sunat_invoice/debit_note.rb +33 -0
- data/lib/sunat_invoice/debit_note_line.rb +15 -0
- data/lib/sunat_invoice/invoice.rb +23 -144
- data/lib/sunat_invoice/item.rb +40 -26
- data/lib/sunat_invoice/line.rb +18 -0
- data/lib/sunat_invoice/provider.rb +20 -14
- data/lib/sunat_invoice/response_parser.rb +64 -0
- data/lib/sunat_invoice/signature.rb +29 -15
- data/lib/sunat_invoice/summary_line.rb +75 -0
- data/lib/sunat_invoice/tax.rb +6 -1
- data/lib/sunat_invoice/trade_calculations.rb +68 -0
- data/lib/sunat_invoice/trade_document.rb +85 -0
- data/lib/sunat_invoice/utils.rb +48 -9
- data/lib/sunat_invoice/voided.rb +22 -0
- data/lib/sunat_invoice/voided_line.rb +20 -0
- data/lib/sunat_invoice/xml_document.rb +52 -0
- data/lib/sunat_invoice.rb +14 -0
- data/sunat_invoice.gemspec +5 -5
- data/test/credit_note_test.rb +15 -0
- data/test/daily_summary_test.rb +35 -0
- data/test/debit_note_test.rb +15 -0
- data/test/factories.rb +70 -0
- data/test/fixtures/responses/invoice_success.xml +2 -0
- data/test/fixtures/responses/summary_success.xml +2 -0
- data/test/fixtures/responses/ticket_invalid.xml +2 -0
- data/test/helper.rb +1 -0
- data/test/invoice_client_test.rb +68 -16
- data/test/invoice_test.rb +19 -10
- data/test/item_test.rb +3 -2
- data/test/response_parser_test.rb +28 -0
- data/test/support/response_helper.rb +18 -0
- data/test/support/signature_helper.rb +15 -8
- metadata +34 -13
    
        data/test/factories.rb
    CHANGED
    
    | @@ -21,6 +21,55 @@ FactoryBot.define do | |
| 21 21 | 
             
                initialize_with { new(attributes) }
         | 
| 22 22 | 
             
              end
         | 
| 23 23 |  | 
| 24 | 
            +
              factory :credit_note_line, class: 'SunatInvoice::CreditNoteLine' do
         | 
| 25 | 
            +
                quantity 10
         | 
| 26 | 
            +
                unit_code 'NIU'
         | 
| 27 | 
            +
                price 20
         | 
| 28 | 
            +
                price_code '01'
         | 
| 29 | 
            +
                description 'Grabadora Externo'
         | 
| 30 | 
            +
                taxes { [build(:tax, amount: 3.6)] }
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              factory :credit_note, class: 'SunatInvoice::CreditNote' do
         | 
| 34 | 
            +
                provider { build(:provider) }
         | 
| 35 | 
            +
                customer { build(:customer) }
         | 
| 36 | 
            +
                document_number 'F001-211'
         | 
| 37 | 
            +
                currency 'PEN'
         | 
| 38 | 
            +
                ref_document_number 'F001-342'
         | 
| 39 | 
            +
                ref_document_type '01'
         | 
| 40 | 
            +
                response_code '01'
         | 
| 41 | 
            +
                document_type '07'
         | 
| 42 | 
            +
                description 'Some awesome product'
         | 
| 43 | 
            +
                lines { [build(:credit_note_line)] }
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              factory :debit_note_line, class: 'SunatInvoice::DebitNoteLine' do
         | 
| 47 | 
            +
                quantity 10
         | 
| 48 | 
            +
                unit_code 'NIU'
         | 
| 49 | 
            +
                price 20
         | 
| 50 | 
            +
                price_code '01'
         | 
| 51 | 
            +
                description 'Ajuste de precio'
         | 
| 52 | 
            +
                taxes { [build(:tax, amount: 3.6)] }
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              factory :debit_note, class: 'SunatInvoice::DebitNote' do
         | 
| 56 | 
            +
                provider { build(:provider) }
         | 
| 57 | 
            +
                customer { build(:customer) }
         | 
| 58 | 
            +
                document_number 'F001-211'
         | 
| 59 | 
            +
                currency 'PEN'
         | 
| 60 | 
            +
                ref_document_number 'F001-342'
         | 
| 61 | 
            +
                ref_document_type '01'
         | 
| 62 | 
            +
                response_code '01'
         | 
| 63 | 
            +
                document_type '08'
         | 
| 64 | 
            +
                description 'Unidades defectuosas'
         | 
| 65 | 
            +
                lines { [build(:debit_note_line)] }
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              factory :daily_summary, class: 'SunatInvoice::DailySummary' do
         | 
| 69 | 
            +
                provider { build(:provider) }
         | 
| 70 | 
            +
                signature { build(:signature, provider: provider) }
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 24 73 | 
             
              factory :provider, class: 'SunatInvoice::Provider' do
         | 
| 25 74 | 
             
                pk_file File.join(File.dirname(__FILE__), 'certs/pk_file')
         | 
| 26 75 | 
             
                cert_file File.join(File.dirname(__FILE__), 'certs/cert_file')
         | 
| @@ -45,4 +94,25 @@ FactoryBot.define do | |
| 45 94 |  | 
| 46 95 | 
             
                initialize_with { new(attributes) }
         | 
| 47 96 | 
             
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              factory :signature, class: 'SunatInvoice::Signature' do
         | 
| 99 | 
            +
                provider { build(:provider) }
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              factory :summary_line, class: 'SunatInvoice::SummaryLine' do
         | 
| 103 | 
            +
                document_type '03'
         | 
| 104 | 
            +
                document_serial 'BD56'
         | 
| 105 | 
            +
                start_document_number 231
         | 
| 106 | 
            +
                end_document_number 239
         | 
| 107 | 
            +
                taxable 2000
         | 
| 108 | 
            +
                taxes { [build(:tax, amount: 360), build(:tax, amount: 0, tax_type: :isc)] }
         | 
| 109 | 
            +
                total_amount 2360
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              factory :voided_line, class: 'SunatInvoice::VoidedLine' do
         | 
| 113 | 
            +
                document_type '03'
         | 
| 114 | 
            +
                document_serial 'BD56'
         | 
| 115 | 
            +
                document_number 231
         | 
| 116 | 
            +
                description 'Anulación documento'
         | 
| 117 | 
            +
              end
         | 
| 48 118 | 
             
            end
         | 
| @@ -0,0 +1,2 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 2 | 
            +
            <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><soap-env:Header/><soap-env:Body><br:sendBillResponse xmlns:br="http://service.sunat.gob.pe"><applicationResponse>UEsDBBQAAgAIACV9hEsAAAAAAgAAAAAAAAAGAAAAZHVtbXkvAwBQSwMEFAACAAgAJX2ES7yR4JPEAwAAmgsAAB0AAABSLTIwMTAwNDU0NTIzLTAxLUZZMDItMjM0LnhtbLVWW3PaOhB+76/wmIfOtMeRbCAEj6EDoXRoe3LhkiZ9U2zFqMWSK4lLzq8/km/YxJlCZzrmQV59++3q210Z78MuWhkbzAVhtGfaZ9A0MPVZQGjYMxfzsXVhfui/8RB3B3G8Ij6SCjjFImZUYEM5U+Ei3jPXnLoMCSJciiIsXBFjnzxleHf9uHKFv8QRcnciqKOyHDNjwzt5It0liyJGP+4kpvoY6lVRYirFntR/9P+IdKjgfi0h+jPCQRhyHCKJ60gD0TOXUsYuANvt9mzbPGM8BA6EEMAuUJhAkLCRowVDcYFPA4kztaXtiaNeAEw3eMViDMy+p6R1F8OvhVLipSm1lLSkaiX73oyEFMk1z2p+VJ6qb7QbDib0ifXfGIZ3iSijSp8V+S/R6F8slywwBquQcSKX0Su0NrChprXwzrd8u0Ub3xRaC6r1M0HCXWR4NCls5blaEeO4wQWyxBK1bSejnOInzNU4YGMxnfRMUxuVec4RFU+MRyI1lE2/DVuRKC9OYIk8+zT0iaTHCKQIwWHm3oiEWMgTFVOKNMo6FTx3aLXG/e83P+SmO4w/Or9itI7vyeK2E/8U191x88s5IL+Gnz53tvbFtjm4nTUfYORfT2d3n9q3lyyEfP7j23b3sBt/v4un+Pw64u17/vl90Nn2eh4oR9H1AUWBVKuBaq+VOyL1eHfDyUZNnvETPxtvh1iiGzWiarwxl28NyqSxjt+lNCUv7wt+Tji9+zbsjpBE6Up7pbOumK/U+AeGvzdl/GlAxVDiP3RO2CZCrDGfYU7QqmzRxKfTl3wTrpT3ah09Yn46W8W7HCBPF+yVAYVaex3Vuv5OAS8vH1BzRam7252M+rbqt5bqwo5+PJBZ012dzkiL6UC7Y9mOBVtzCN3kl0ELyN5jTpRANbDEnsDyr9MBd4qtbFbgCYHddlu2a8MqOONGvlvSJzuLtswWV4N56XQFkPHnG8Tlc2pLlpNAyVh8bwoalWdTPU633d4Tgde98o20X7RDsiplku6AAyR4LTk1pkSiVXHAgZTIX0ZJzfW+Li6naLWf3iSqumP7jQMNtC0NVOMEfhcMHOqsXzENMP87UoLaAFPsY7I5JSaErXar7TSPjlkTYsT8tVYhb7w8l+ItacpMSxVi/AAdy2kWvb3fqbT2JQvUzFR7OrElqBEWPidxktlXZIyRr4RHBlWZcGbkIf4xlsgQJGAG8nEsUYBSvrJ3fq5y8vsjVfrmRfKFYHUOqVokJsp+ZEXOLQc63SZ0LlrQPqUmlSigviqg/q91/39QSwECAAAUAAIACAAlfYRLAAAAAAIAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAZHVtbXkvUEsBAgAAFAACAAgAJX2ES7yR4JPEAwAAmgsAAB0AAAAAAAAAAQAAAAAAJgAAAFItMjAxMDA0NTQ1MjMtMDEtRlkwMi0yMzQueG1sUEsFBgAAAAACAAIAfwAAACUEAAAAAA==</applicationResponse></br:sendBillResponse></soap-env:Body></soap-env:Envelope>
         | 
| @@ -0,0 +1,2 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 2 | 
            +
            <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><soap-env:Header/><soap-env:Body><br:sendSummaryResponse xmlns:br="http://service.sunat.gob.pe"><ticket>1512600172234</ticket></br:sendSummaryResponse></soap-env:Body></soap-env:Envelope>
         | 
| @@ -0,0 +1,2 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 2 | 
            +
            <S:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getStatusResponse xmlns:ns2="http://service.sunat.gob.pe"><status><content>El ticket no existe</content><statusCode>0127</statusCode></status></ns2:getStatusResponse></S:Body></S:Envelope>
         | 
    
        data/test/helper.rb
    CHANGED
    
    
    
        data/test/invoice_client_test.rb
    CHANGED
    
    | @@ -4,38 +4,90 @@ require_relative 'helper' | |
| 4 4 |  | 
| 5 5 | 
             
            scope 'SunatInvoice::InvoiceClient' do
         | 
| 6 6 | 
             
              setup do
         | 
| 7 | 
            -
                provider = FactoryBot.build(:provider,
         | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
                customer = FactoryBot.build(:customer,
         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 7 | 
            +
                @provider = FactoryBot.build(:provider,
         | 
| 8 | 
            +
                                             signature_id: 'signatureST',
         | 
| 9 | 
            +
                                             signature_location_id: 'signQWI3',
         | 
| 10 | 
            +
                                             ruc: '20100454523',
         | 
| 11 | 
            +
                                             name: 'SOPORTE TECNOLOGICO EIRL')
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                @customer = FactoryBot.build(:customer,
         | 
| 14 | 
            +
                                             ruc: '20293028401',
         | 
| 15 | 
            +
                                             name: 'SOME BUSINESS')
         | 
| 16 16 | 
             
                SunatInvoice.configure do |c|
         | 
| 17 | 
            -
                  c.account_ruc = provider.ruc
         | 
| 17 | 
            +
                  c.account_ruc = @provider.ruc
         | 
| 18 18 | 
             
                  c.account_user = 'MODDATOS'
         | 
| 19 19 | 
             
                  c.account_password = 'moddatos'
         | 
| 20 | 
            -
                  c.provider = provider
         | 
| 21 20 | 
             
                end
         | 
| 22 21 | 
             
                @client = SunatInvoice::InvoiceClient.new
         | 
| 23 22 |  | 
| 24 23 | 
             
                tax = SunatInvoice::Tax.new(amount: 3.6, tax_type: :igv)
         | 
| 25 24 | 
             
                item = FactoryBot.build(:item, taxes: [tax])
         | 
| 26 | 
            -
                @invoice = SunatInvoice::Invoice.new(provider: provider,
         | 
| 27 | 
            -
                                                     customer: customer,
         | 
| 25 | 
            +
                @invoice = SunatInvoice::Invoice.new(provider: @provider,
         | 
| 26 | 
            +
                                                     customer: @customer,
         | 
| 28 27 | 
             
                                                     document_number: 'FY02-234')
         | 
| 29 | 
            -
                @invoice. | 
| 28 | 
            +
                @invoice.lines << item
         | 
| 30 29 | 
             
              end
         | 
| 31 30 |  | 
| 32 31 | 
             
              test 'should use dev service when not define environment' do
         | 
| 33 32 | 
             
                assert_equal @client.wsdl, @client.dev_server
         | 
| 34 33 | 
             
              end
         | 
| 35 34 |  | 
| 35 | 
            +
              test 'send invoice success' do
         | 
| 36 | 
            +
                response = @client.dispatch(@invoice)
         | 
| 37 | 
            +
                assert_equal response.http.code, 200
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              test 'send credit note' do
         | 
| 41 | 
            +
                tax = SunatInvoice::Tax.new(amount: 3.6, tax_type: :igv)
         | 
| 42 | 
            +
                line = FactoryBot.build(:credit_note_line, taxes: [tax])
         | 
| 43 | 
            +
                signature = FactoryBot.build(:signature, provider: @provider)
         | 
| 44 | 
            +
                credit_note = FactoryBot.build(:credit_note, provider: @provider,
         | 
| 45 | 
            +
                                                             customer: @customer,
         | 
| 46 | 
            +
                                                             lines: [line],
         | 
| 47 | 
            +
                                                             signature: signature)
         | 
| 48 | 
            +
                response = @client.dispatch(credit_note)
         | 
| 49 | 
            +
                assert_equal response.http.code, 200
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              test 'send debit note' do
         | 
| 53 | 
            +
                tax = SunatInvoice::Tax.new(amount: 3.6, tax_type: :igv)
         | 
| 54 | 
            +
                line = FactoryBot.build(:debit_note_line, taxes: [tax])
         | 
| 55 | 
            +
                signature = FactoryBot.build(:signature, provider: @provider)
         | 
| 56 | 
            +
                debit_note = FactoryBot.build(:debit_note, provider: @provider,
         | 
| 57 | 
            +
                                                           customer: @customer,
         | 
| 58 | 
            +
                                                           lines: [line],
         | 
| 59 | 
            +
                                                           signature: signature)
         | 
| 60 | 
            +
                response = @client.dispatch(debit_note)
         | 
| 61 | 
            +
                assert_equal response.http.code, 200
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              test 'send summary success' do
         | 
| 65 | 
            +
                line = FactoryBot.build(:summary_line)
         | 
| 66 | 
            +
                signature = FactoryBot.build(:signature, provider: @provider)
         | 
| 67 | 
            +
                summary = SunatInvoice::DailySummary.new(provider: @provider,
         | 
| 68 | 
            +
                                                         signature: signature,
         | 
| 69 | 
            +
                                                         reference_date: Date.today,
         | 
| 70 | 
            +
                                                         currency: 'PEN',
         | 
| 71 | 
            +
                                                         lines: [line])
         | 
| 72 | 
            +
                response = @client.dispatch(summary)
         | 
| 73 | 
            +
                assert_equal response.http.code, 200
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              test 'void document' do
         | 
| 77 | 
            +
                line = FactoryBot.build(:voided_line)
         | 
| 78 | 
            +
                signature = FactoryBot.build(:signature, provider: @provider)
         | 
| 79 | 
            +
                voided = SunatInvoice::Voided.new(provider: @provider,
         | 
| 80 | 
            +
                                                  signature: signature,
         | 
| 81 | 
            +
                                                  reference_date: Date.today,
         | 
| 82 | 
            +
                                                  currency: 'PEN',
         | 
| 83 | 
            +
                                                  lines: [line])
         | 
| 84 | 
            +
                response = @client.dispatch(voided)
         | 
| 85 | 
            +
                assert_equal response.http.code, 200
         | 
| 86 | 
            +
              end
         | 
| 36 87 |  | 
| 37 | 
            -
              test ' | 
| 38 | 
            -
                 | 
| 88 | 
            +
              test 'get status' do
         | 
| 89 | 
            +
                ticket = rand(10**15).to_s
         | 
| 90 | 
            +
                response = @client.get_status(ticket)
         | 
| 39 91 | 
             
                assert_equal response.http.code, 200
         | 
| 40 92 | 
             
              end
         | 
| 41 93 | 
             
            end
         | 
    
        data/test/invoice_test.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: false
         | 
| 2 | 
            +
             | 
| 2 3 | 
             
            require_relative 'helper'
         | 
| 3 4 | 
             
            include SunatInvoice
         | 
| 4 5 |  | 
| @@ -7,7 +8,7 @@ setup do | |
| 7 8 | 
             
              @invoice = FactoryBot.build(:invoice, provider: @provider)
         | 
| 8 9 | 
             
              tax = SunatInvoice::Tax.new(amount: 3.6, tax_type: :igv)
         | 
| 9 10 | 
             
              item_attr = { quantity: 10, price: 20, price_code: '01', taxes: [tax] }
         | 
| 10 | 
            -
              @invoice. | 
| 11 | 
            +
              @invoice.lines << SunatInvoice::Item.new(item_attr)
         | 
| 11 12 | 
             
              @parsed_xml = Nokogiri::XML(@invoice.xml, &:noblanks)
         | 
| 12 13 | 
             
            end
         | 
| 13 14 |  | 
| @@ -27,7 +28,7 @@ end | |
| 27 28 |  | 
| 28 29 | 
             
            test 'has a date' do
         | 
| 29 30 | 
             
              date = @parsed_xml.xpath('//cbc:IssueDate')
         | 
| 30 | 
            -
              assert_equal date.first.content,  | 
| 31 | 
            +
              assert_equal date.first.content, Date.today.strftime('%Y-%m-%d')
         | 
| 31 32 | 
             
            end
         | 
| 32 33 |  | 
| 33 34 | 
             
            test 'has a signature' do
         | 
| @@ -110,7 +111,7 @@ test 'has at least one item' do | |
| 110 111 | 
             
            end
         | 
| 111 112 |  | 
| 112 113 | 
             
            test 'has total by kind of sale' do
         | 
| 113 | 
            -
              tag = '//ext: | 
| 114 | 
            +
              tag = '//ext:UBLExtension/ext:ExtensionContent/sac:AdditionalInformation'
         | 
| 114 115 | 
             
              additional_info = @parsed_xml.xpath(tag)
         | 
| 115 116 | 
             
              assert additional_info.count.positive?
         | 
| 116 117 | 
             
              assert_equal additional_info.first.children.count, 1
         | 
| @@ -123,16 +124,16 @@ test 'has total tag' do | |
| 123 124 | 
             
              assert total.count.positive?
         | 
| 124 125 | 
             
            end
         | 
| 125 126 |  | 
| 126 | 
            -
            test '# | 
| 127 | 
            +
            test '#calculate_taxes_totals' do
         | 
| 127 128 | 
             
              tax = FactoryBot.build(:tax, amount: 15)
         | 
| 128 129 | 
             
              invoice = FactoryBot.build(:invoice)
         | 
| 129 130 | 
             
              2.times do
         | 
| 130 | 
            -
                invoice. | 
| 131 | 
            +
                invoice.lines << FactoryBot.build(:item, taxes: [tax])
         | 
| 131 132 | 
             
              end
         | 
| 132 | 
            -
              invoice. | 
| 133 | 
            -
               | 
| 134 | 
            -
              assert_equal  | 
| 135 | 
            -
              assert_equal  | 
| 133 | 
            +
              invoice.calculate_taxes_totals
         | 
| 134 | 
            +
              taxes_totals = invoice.instance_variable_get('@taxes_totals')
         | 
| 135 | 
            +
              assert_equal taxes_totals.count, 1
         | 
| 136 | 
            +
              assert_equal taxes_totals[:igv], 300
         | 
| 136 137 | 
             
            end
         | 
| 137 138 |  | 
| 138 139 | 
             
            test '#get_total_igv_code' do
         | 
| @@ -140,6 +141,14 @@ test '#get_total_igv_code' do | |
| 140 141 | 
             
              assert_equal invoice.get_total_igv_code('11'), '1004'
         | 
| 141 142 | 
             
              assert_equal invoice.get_total_igv_code('15'), '1004'
         | 
| 142 143 | 
             
              assert_equal invoice.get_total_igv_code('20'), '1003'
         | 
| 143 | 
            -
              assert_equal invoice.get_total_igv_code(' | 
| 144 | 
            +
              assert_equal invoice.get_total_igv_code('30'), '1002'
         | 
| 145 | 
            +
              assert_equal invoice.get_total_igv_code('32'), '1004'
         | 
| 144 146 | 
             
              assert invoice.get_total_igv_code('42').nil?
         | 
| 145 147 | 
             
            end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            test 'could have discounts' do
         | 
| 150 | 
            +
              @invoice.discount = 25
         | 
| 151 | 
            +
              parsed_xml = Nokogiri::XML(@invoice.xml, &:noblanks)
         | 
| 152 | 
            +
              discount_node = parsed_xml.xpath('//sac:AdditionalMonetaryTotal').last
         | 
| 153 | 
            +
              assert_equal discount_node.at_xpath('descendant::cbc:ID').content, '2005'
         | 
| 154 | 
            +
            end
         | 
    
        data/test/item_test.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 2 3 | 
             
            require_relative 'helper'
         | 
| 3 4 | 
             
            include SunatInvoice
         | 
| 4 5 |  | 
| @@ -13,7 +14,7 @@ end | |
| 13 14 | 
             
            def invoice_setup
         | 
| 14 15 | 
             
              # add item to invoice in order to setup namespaces
         | 
| 15 16 | 
             
              invoice = FactoryBot.build(:invoice)
         | 
| 16 | 
            -
              invoice. | 
| 17 | 
            +
              invoice.lines << @item
         | 
| 17 18 | 
             
              invoice_xml = Nokogiri::XML(invoice.xml, &:noblanks)
         | 
| 18 19 | 
             
              @item_xml = invoice_xml.xpath('//cac:InvoiceLine')
         | 
| 19 20 | 
             
            end
         | 
| @@ -104,7 +105,7 @@ scope '#sale_taxes' do | |
| 104 105 | 
             
              test 'has sum by tax_type' do
         | 
| 105 106 | 
             
                @item.taxes << SunatInvoice::Tax.new(amount: 5, tax_type: :isc)
         | 
| 106 107 | 
             
                assert_equal @item.sale_taxes.count, 2
         | 
| 107 | 
            -
                assert_equal @item.sale_taxes.keys, [ | 
| 108 | 
            +
                assert_equal @item.sale_taxes.keys, %i[igv isc]
         | 
| 108 109 | 
             
                assert_equal @item.sale_taxes.values, [21.6, 10]
         | 
| 109 110 | 
             
              end
         | 
| 110 111 | 
             
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative 'helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            scope 'SunatInvoice::ResponseParser' do
         | 
| 6 | 
            +
              test 'invoice success response' do
         | 
| 7 | 
            +
                response_xml = ResponseHelper.load('invoice_success.xml')
         | 
| 8 | 
            +
                body = ResponseHelper.parse(response_xml)
         | 
| 9 | 
            +
                response = SunatInvoice::ResponseParser.new(body, 'invoice')
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                assert_equal response.status_code, '0'
         | 
| 12 | 
            +
                assert response.message.include?('aceptada')
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              test 'summary success response' do
         | 
| 16 | 
            +
                response_xml = ResponseHelper.load('summary_success.xml')
         | 
| 17 | 
            +
                body = ResponseHelper.parse(response_xml)
         | 
| 18 | 
            +
                response = SunatInvoice::ResponseParser.new(body, 'summary')
         | 
| 19 | 
            +
                assert response.ticket.length.positive?
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              test 'get_status response' do
         | 
| 23 | 
            +
                response_xml = ResponseHelper.load('ticket_invalid.xml')
         | 
| 24 | 
            +
                body = ResponseHelper.parse(response_xml)
         | 
| 25 | 
            +
                response = SunatInvoice::ResponseParser.new(body, 'status')
         | 
| 26 | 
            +
                assert_equal response.message, 'El ticket no existe'
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'nori'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module ResponseHelper
         | 
| 6 | 
            +
              def self.load(file_name)
         | 
| 7 | 
            +
                File.read("#{Dir.pwd}/test/fixtures/responses/#{file_name}")
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def self.parse(response_xml)
         | 
| 11 | 
            +
                parser = Nori.new(delete_namespace_attributes: true,
         | 
| 12 | 
            +
                                  convert_tags_to: ->(tag) { tag.snakecase.to_sym },
         | 
| 13 | 
            +
                                  strip_namespaces: true)
         | 
| 14 | 
            +
                hash = parser.parse(response_xml)
         | 
| 15 | 
            +
                envelope = parser.find(hash, 'Envelope')
         | 
| 16 | 
            +
                parser.find(envelope, 'Body')
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -1,6 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module SignatureHelper
         | 
| 2 4 | 
             
              def self.generate_keys
         | 
| 5 | 
            +
                return if exists?('pk_file')
         | 
| 6 | 
            +
             | 
| 3 7 | 
             
                pk = OpenSSL::PKey::RSA.new 2048
         | 
| 8 | 
            +
                cert = generate_certificate(pk)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                cert_dir = "#{File.dirname(__FILE__)}/../certs"
         | 
| 11 | 
            +
                Dir.mkdir(cert_dir) unless Dir.exist?(cert_dir)
         | 
| 12 | 
            +
                File.open(file('pk_file'), 'w') { |f| f.puts pk.to_pem }
         | 
| 13 | 
            +
                File.open(file('cert_file'), 'w') { |f| f.puts cert.to_pem }
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def self.generate_certificate(pk)
         | 
| 4 17 | 
             
                name = OpenSSL::X509::Name.parse('CN=example.com/C=EE')
         | 
| 5 18 | 
             
                cert = OpenSSL::X509::Certificate.new
         | 
| 6 19 | 
             
                cert.version    = 2
         | 
| @@ -11,13 +24,7 @@ module SignatureHelper | |
| 11 24 | 
             
                cert.subject    = name
         | 
| 12 25 | 
             
                cert.issuer     = name
         | 
| 13 26 | 
             
                cert.sign pk, OpenSSL::Digest::SHA1.new
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                unless exists?('pk_file')
         | 
| 16 | 
            -
                  cert_dir = "#{File.dirname(__FILE__)}/../certs"
         | 
| 17 | 
            -
                  Dir.mkdir(cert_dir) unless Dir.exist?(cert_dir)
         | 
| 18 | 
            -
                  File.open(file('pk_file'), 'w') { |f| f.puts pk.to_pem  }
         | 
| 19 | 
            -
                  File.open(file('cert_file'), 'w') { |f| f.puts cert.to_pem  }
         | 
| 20 | 
            -
                end
         | 
| 27 | 
            +
                cert
         | 
| 21 28 | 
             
              end
         | 
| 22 29 |  | 
| 23 30 | 
             
              def self.file(name)
         | 
| @@ -25,6 +32,6 @@ module SignatureHelper | |
| 25 32 | 
             
              end
         | 
| 26 33 |  | 
| 27 34 | 
             
              def self.exists?(name)
         | 
| 28 | 
            -
                File. | 
| 35 | 
            +
                File.exist?(file(name))
         | 
| 29 36 | 
             
              end
         | 
| 30 37 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,57 +1,57 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: sunat_invoice
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - César Carruitero
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2017-12- | 
| 11 | 
            +
            date: 2017-12-12 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            -
              name:  | 
| 14 | 
            +
              name: nokogiri
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 17 | 
             
                - - "~>"
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version:  | 
| 19 | 
            +
                    version: '1.8'
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 24 | 
             
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version:  | 
| 26 | 
            +
                    version: '1.8'
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            -
              name:  | 
| 28 | 
            +
              name: rubyzip
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 30 | 
             
                requirements:
         | 
| 31 31 | 
             
                - - "~>"
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: '1. | 
| 33 | 
            +
                    version: '1.2'
         | 
| 34 34 | 
             
              type: :runtime
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 38 | 
             
                - - "~>"
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: '1. | 
| 40 | 
            +
                    version: '1.2'
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            -
              name:  | 
| 42 | 
            +
              name: savon
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 44 | 
             
                requirements:
         | 
| 45 45 | 
             
                - - "~>"
         | 
| 46 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version:  | 
| 47 | 
            +
                    version: '2.11'
         | 
| 48 48 | 
             
              type: :runtime
         | 
| 49 49 | 
             
              prerelease: false
         | 
| 50 50 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 51 | 
             
                requirements:
         | 
| 52 52 | 
             
                - - "~>"
         | 
| 53 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version:  | 
| 54 | 
            +
                    version: '2.11'
         | 
| 55 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 56 | 
             
              name: xmldsig
         | 
| 57 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -136,7 +136,7 @@ dependencies: | |
| 136 136 | 
             
                - - "~>"
         | 
| 137 137 | 
             
                  - !ruby/object:Gem::Version
         | 
| 138 138 | 
             
                    version: '0.51'
         | 
| 139 | 
            -
            description:  | 
| 139 | 
            +
            description: Generate and send Electronic Invoices to SUNAT
         | 
| 140 140 | 
             
            email:
         | 
| 141 141 | 
             
            - cesar@mozilla.pe
         | 
| 142 142 | 
             
            executables: []
         | 
| @@ -156,21 +156,42 @@ files: | |
| 156 156 | 
             
            - lib/sunat_invoice/clients/invoice_client.rb
         | 
| 157 157 | 
             
            - lib/sunat_invoice/clients/validate_client.rb
         | 
| 158 158 | 
             
            - lib/sunat_invoice/configuration.rb
         | 
| 159 | 
            +
            - lib/sunat_invoice/credit_note.rb
         | 
| 160 | 
            +
            - lib/sunat_invoice/credit_note_line.rb
         | 
| 159 161 | 
             
            - lib/sunat_invoice/customer.rb
         | 
| 162 | 
            +
            - lib/sunat_invoice/daily_summary.rb
         | 
| 163 | 
            +
            - lib/sunat_invoice/debit_note.rb
         | 
| 164 | 
            +
            - lib/sunat_invoice/debit_note_line.rb
         | 
| 160 165 | 
             
            - lib/sunat_invoice/invoice.rb
         | 
| 161 166 | 
             
            - lib/sunat_invoice/item.rb
         | 
| 167 | 
            +
            - lib/sunat_invoice/line.rb
         | 
| 162 168 | 
             
            - lib/sunat_invoice/model.rb
         | 
| 163 169 | 
             
            - lib/sunat_invoice/provider.rb
         | 
| 170 | 
            +
            - lib/sunat_invoice/response_parser.rb
         | 
| 164 171 | 
             
            - lib/sunat_invoice/signature.rb
         | 
| 172 | 
            +
            - lib/sunat_invoice/summary_line.rb
         | 
| 165 173 | 
             
            - lib/sunat_invoice/tax.rb
         | 
| 174 | 
            +
            - lib/sunat_invoice/trade_calculations.rb
         | 
| 175 | 
            +
            - lib/sunat_invoice/trade_document.rb
         | 
| 166 176 | 
             
            - lib/sunat_invoice/tributer.rb
         | 
| 167 177 | 
             
            - lib/sunat_invoice/utils.rb
         | 
| 178 | 
            +
            - lib/sunat_invoice/voided.rb
         | 
| 179 | 
            +
            - lib/sunat_invoice/voided_line.rb
         | 
| 180 | 
            +
            - lib/sunat_invoice/xml_document.rb
         | 
| 168 181 | 
             
            - sunat_invoice.gemspec
         | 
| 182 | 
            +
            - test/credit_note_test.rb
         | 
| 183 | 
            +
            - test/daily_summary_test.rb
         | 
| 184 | 
            +
            - test/debit_note_test.rb
         | 
| 169 185 | 
             
            - test/factories.rb
         | 
| 186 | 
            +
            - test/fixtures/responses/invoice_success.xml
         | 
| 187 | 
            +
            - test/fixtures/responses/summary_success.xml
         | 
| 188 | 
            +
            - test/fixtures/responses/ticket_invalid.xml
         | 
| 170 189 | 
             
            - test/helper.rb
         | 
| 171 190 | 
             
            - test/invoice_client_test.rb
         | 
| 172 191 | 
             
            - test/invoice_test.rb
         | 
| 173 192 | 
             
            - test/item_test.rb
         | 
| 193 | 
            +
            - test/response_parser_test.rb
         | 
| 194 | 
            +
            - test/support/response_helper.rb
         | 
| 174 195 | 
             
            - test/support/signature_helper.rb
         | 
| 175 196 | 
             
            homepage: https://github.com/ccarruitero/sunat_invoice
         | 
| 176 197 | 
             
            licenses:
         | 
| @@ -195,5 +216,5 @@ rubyforge_project: | |
| 195 216 | 
             
            rubygems_version: 2.6.13
         | 
| 196 217 | 
             
            signing_key: 
         | 
| 197 218 | 
             
            specification_version: 4
         | 
| 198 | 
            -
            summary:  | 
| 219 | 
            +
            summary: Ruby gem to use SUNAT Electronic Billing from your app
         | 
| 199 220 | 
             
            test_files: []
         |