extface 0.1.7 → 0.1.8
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/app/controllers/extface/devices_controller.rb +14 -0
 - data/app/controllers/extface/handler_controller.rb +1 -1
 - data/app/models/extface/driver/daisy/commands_fx1200.rb +11 -2
 - data/app/models/extface/driver/daisy_fx1200.rb +261 -15
 - data/app/models/extface/driver/epson/fiscal.rb +72 -0
 - data/app/views/extface/devices/show.html.erb +7 -0
 - data/config/routes.rb +1 -0
 - data/lib/extface/version.rb +1 -1
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 900544046448abb9c9c713e46a328fb7024a6d7b
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: bb25d5f73e3cc268ee61178863c9a40768afa006
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: f8e3ab792ef789a4a5ae4999ce42837b53b1c898a8f588306f660bf8f59a9707427177b962932800ead930d957f30df9ad0ed1c628cddc40ce16b82cab1d95b1
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 77251dc8768f3ad7645a46d740a8d0b89cbc5082e97129116a59fa47f62de4822f7a51228fd6612ccd838577ab339dfe10c655f0a445bb76b1700d393d7f4857
         
     | 
| 
         @@ -54,6 +54,20 @@ module Extface 
     | 
|
| 
       54 
54 
     | 
    
         
             
                  @job = @device.driver.print_test_page if params[:test_page]
         
     | 
| 
       55 
55 
     | 
    
         
             
                  render action: :show
         
     | 
| 
       56 
56 
     | 
    
         
             
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
                
         
     | 
| 
      
 58 
     | 
    
         
            +
                def fiscal
         
     | 
| 
      
 59 
     | 
    
         
            +
                  set_device
         
     | 
| 
      
 60 
     | 
    
         
            +
                  if @device.fiscal?
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @job = case
         
     | 
| 
      
 62 
     | 
    
         
            +
                      when params[:non_fiscal_test].present? then @device.driver.non_fiscal_test
         
     | 
| 
      
 63 
     | 
    
         
            +
                      when params[:fiscal_test].present? then @device.driver.fiscal_test
         
     | 
| 
      
 64 
     | 
    
         
            +
                      when params[:x_report].present? then @device.driver.x_report_session
         
     | 
| 
      
 65 
     | 
    
         
            +
                      when params[:z_report].present? then @device.driver.z_report_session
         
     | 
| 
      
 66 
     | 
    
         
            +
                      when params[:cancel_fiscal_doc].present? then @device.driver.cancel_doc_session
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  render action: :show
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
       57 
71 
     | 
    
         | 
| 
       58 
72 
     | 
    
         
             
                private
         
     | 
| 
       59 
73 
     | 
    
         
             
                  # Use callbacks to share common setup or constraints between actions.
         
     | 
| 
         @@ -33,7 +33,7 @@ module Extface 
     | 
|
| 
       33 
33 
     | 
    
         
             
                      r.append device.uuid, request.body.read
         
     | 
| 
       34 
34 
     | 
    
         
             
                      @full_buffer = r.get device.uuid
         
     | 
| 
       35 
35 
     | 
    
         
             
                    end
         
     | 
| 
       36 
     | 
    
         
            -
                    if bytes_porcessed = device.driver.handle(@full_buffer)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    if bytes_porcessed = device.driver.handle(@full_buffer.b)
         
     | 
| 
       37 
37 
     | 
    
         
             
                      Extface.redis_block do |r|
         
     | 
| 
       38 
38 
     | 
    
         
             
                        r.set device.uuid, r.get(device.uuid)[bytes_porcessed]
         
     | 
| 
       39 
39 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -1,5 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Extface
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Driver::Daisy::CommandsFx1200
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
                STX = 0x01
         
     | 
| 
      
 5 
     | 
    
         
            +
                PA1 = 0x05
         
     | 
| 
      
 6 
     | 
    
         
            +
                PA2 = 0x04
         
     | 
| 
      
 7 
     | 
    
         
            +
                ETX = 0x03
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                NAK = 0x15
         
     | 
| 
      
 10 
     | 
    
         
            +
                SYN = 0x16
         
     | 
| 
      
 11 
     | 
    
         
            +
                
         
     | 
| 
       3 
12 
     | 
    
         
             
                module Init
         
     | 
| 
       4 
13 
     | 
    
         
             
                  DATE_TIME           = 0x3d
         
     | 
| 
       5 
14 
     | 
    
         
             
                  PRINT_OPTIONS       = 0x2b
         
     | 
| 
         @@ -81,8 +90,8 @@ module Extface 
     | 
|
| 
       81 
90 
     | 
    
         
             
                end
         
     | 
| 
       82 
91 
     | 
    
         | 
| 
       83 
92 
     | 
    
         
             
                module Printer
         
     | 
| 
       84 
     | 
    
         
            -
                   
     | 
| 
       85 
     | 
    
         
            -
                   
     | 
| 
      
 93 
     | 
    
         
            +
                  MOVE   = 0x2c
         
     | 
| 
      
 94 
     | 
    
         
            +
                  CUT  = 0x2d
         
     | 
| 
       86 
95 
     | 
    
         
             
                end
         
     | 
| 
       87 
96 
     | 
    
         | 
| 
       88 
97 
     | 
    
         
             
                module Other
         
     | 
| 
         @@ -21,32 +21,278 @@ module Extface 
     | 
|
| 
       21 
21 
     | 
    
         
             
                RAW = true  #responds to #push(data) and #pull
         
     | 
| 
       22 
22 
     | 
    
         
             
                PRINT = false #POS, slip printers
         
     | 
| 
       23 
23 
     | 
    
         
             
                FISCAL = true #cash registers, fiscal printers
         
     | 
| 
       24 
     | 
    
         
            -
                REPORT = false #only transmit data that must be parsed by handler, CDR, report devices 
     | 
| 
      
 24 
     | 
    
         
            +
                REPORT = false #only transmit data that must be parsed by handler, CDR, report devices  
         
     | 
| 
      
 25 
     | 
    
         
            +
                
         
     | 
| 
      
 26 
     | 
    
         
            +
                RESPONSE_TIMEOUT = 6  #seconds
         
     | 
| 
      
 27 
     | 
    
         
            +
                INVALID_FRAME_RETRIES = 6  #seconds
         
     | 
| 
      
 28 
     | 
    
         
            +
                
         
     | 
| 
      
 29 
     | 
    
         
            +
                TAX_GROUPS_MAP = {
         
     | 
| 
      
 30 
     | 
    
         
            +
                  1 => "\xc0",
         
     | 
| 
      
 31 
     | 
    
         
            +
                  2 => "\xc1",
         
     | 
| 
      
 32 
     | 
    
         
            +
                  3 => "\xc2",
         
     | 
| 
      
 33 
     | 
    
         
            +
                  4 => "\xc3",
         
     | 
| 
      
 34 
     | 
    
         
            +
                  5 => "\xc4",
         
     | 
| 
      
 35 
     | 
    
         
            +
                  6 => "\xc5",
         
     | 
| 
      
 36 
     | 
    
         
            +
                  7 => "\xc6",
         
     | 
| 
      
 37 
     | 
    
         
            +
                  8 => "\xc7"
         
     | 
| 
      
 38 
     | 
    
         
            +
                }
         
     | 
| 
       25 
39 
     | 
    
         | 
| 
       26 
40 
     | 
    
         
             
                has_serial_config
         
     | 
| 
      
 41 
     | 
    
         
            +
                
         
     | 
| 
      
 42 
     | 
    
         
            +
                include Extface::Driver::Daisy::CommandsFx1200
         
     | 
| 
       27 
43 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                def handle(buffer)
         
     | 
| 
       29 
     | 
    
         
            -
                   
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
                def handle(buffer) #buffer is filled with multiple pushes, wait for full frame (ACKs)STX..PA2..PA1..ETX
         
     | 
| 
      
 45 
     | 
    
         
            +
                  if buffer[/^\x16+$/] # skip if only ACKs
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return buffer.length 
         
     | 
| 
      
 47 
     | 
    
         
            +
                  else
         
     | 
| 
      
 48 
     | 
    
         
            +
                    if frame_len = buffer.index("\x03") || buffer.index("\x15")
         
     | 
| 
      
 49 
     | 
    
         
            +
                      rpush buffer[0..frame_len]
         
     | 
| 
      
 50 
     | 
    
         
            +
                      return frame_len+1 # return number of bytes processed
         
     | 
| 
      
 51 
     | 
    
         
            +
                    else
         
     | 
| 
      
 52 
     | 
    
         
            +
                      #TODO check buffer.length
         
     | 
| 
      
 53 
     | 
    
         
            +
                      return 0 #no bytes processed
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  return buffer.length 
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
                
         
     | 
| 
      
 59 
     | 
    
         
            +
                def autocut(partial = true) # return "P" - success, "F" - failed
         
     | 
| 
      
 60 
     | 
    
         
            +
                  resp = fsend(Printer::CUT)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  resp == "P"
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
                 
         
     | 
| 
      
 64 
     | 
    
         
            +
                def non_fiscal_test
         
     | 
| 
      
 65 
     | 
    
         
            +
                  device.session("Non Fiscal Text") do |s|
         
     | 
| 
      
 66 
     | 
    
         
            +
                    s.notify "Printing Non Fiscal Text"
         
     | 
| 
      
 67 
     | 
    
         
            +
                    s.fsend Sales::START_NON_FISCAL_DOC
         
     | 
| 
      
 68 
     | 
    
         
            +
                    s.fsend Sales::PRINT_NON_FISCAL_TEXT, "********************************"
         
     | 
| 
      
 69 
     | 
    
         
            +
                    s.fsend Sales::PRINT_NON_FISCAL_TEXT, "Extface Print Test".center(32)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    s.fsend Sales::PRINT_NON_FISCAL_TEXT, "********************************"
         
     | 
| 
      
 71 
     | 
    
         
            +
                    s.fsend Printer::MOVE, "1"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    s.fsend Sales::PRINT_NON_FISCAL_TEXT, "Driver: " + "#{self.class::NAME}".truncate(24)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    s.fsend(Sales::END_NON_FISCAL_DOC)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    s.notify "Printing finished"
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
                
         
     | 
| 
      
 78 
     | 
    
         
            +
                def fiscal_test
         
     | 
| 
      
 79 
     | 
    
         
            +
                  sale_and_pay_items_session([
         
     | 
| 
      
 80 
     | 
    
         
            +
                    { price: 0.01, text1: "Extface Test" }
         
     | 
| 
      
 81 
     | 
    
         
            +
                  ])
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
                
         
     | 
| 
      
 84 
     | 
    
         
            +
                def build_sale_data(price, text1 = nil, text2 = nil, tax_group = 2, qty = nil, percent = nil, neto = nil)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  "".tap() do |data|
         
     | 
| 
      
 86 
     | 
    
         
            +
                    data << text1 unless text1.blank?
         
     | 
| 
      
 87 
     | 
    
         
            +
                    data << "\x0a#{text2}" unless text2.blank?
         
     | 
| 
      
 88 
     | 
    
         
            +
                    data << "\t"
         
     | 
| 
      
 89 
     | 
    
         
            +
                    data << TAX_GROUPS_MAP[tax_group || 2]
         
     | 
| 
      
 90 
     | 
    
         
            +
                    data << price.to_s
         
     | 
| 
      
 91 
     | 
    
         
            +
                    data << "*#{qty.to_s}" unless qty.blank?
         
     | 
| 
      
 92 
     | 
    
         
            +
                    data << ",#{percent}" unless percent.blank?
         
     | 
| 
      
 93 
     | 
    
         
            +
                    data << "$#{neto}" unless neto.blank?
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
                
         
     | 
| 
      
 97 
     | 
    
         
            +
                def sale_and_pay_items_session(items = [], operator = "1", password = "1")
         
     | 
| 
      
 98 
     | 
    
         
            +
                  device.session("Fiscal Doc") do |s|
         
     | 
| 
      
 99 
     | 
    
         
            +
                    s.notify "Fiscal Doc Start"
         
     | 
| 
      
 100 
     | 
    
         
            +
                    s.fsend Sales::START_FISCAL_DOC, "#{operator},#{password},00001"
         
     | 
| 
      
 101 
     | 
    
         
            +
                    items.each do |item|
         
     | 
| 
      
 102 
     | 
    
         
            +
                      s.fsend Sales::SALE_AND_SHOW, build_sale_data(item[:price], item[:text1], item[:text2], item[:tax_group], item[:qty], item[:percent], item[:neto])
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
                    s.fsend(Sales::TOTAL, "\t")
         
     | 
| 
      
 105 
     | 
    
         
            +
                    s.fsend(Sales::END_FISCAL_DOC)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    s.notify "Fiscal Doc End"
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
                
         
     | 
| 
      
 110 
     | 
    
         
            +
                def z_report_session
         
     | 
| 
      
 111 
     | 
    
         
            +
                  device.session("Z Report") do |s|
         
     | 
| 
      
 112 
     | 
    
         
            +
                    s.notify "Z Report Start"
         
     | 
| 
      
 113 
     | 
    
         
            +
                    s.fsend Closure::DAY_FIN_REPORT, "0"
         
     | 
| 
      
 114 
     | 
    
         
            +
                    s.notify "Z Report End"
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
                
         
     | 
| 
      
 118 
     | 
    
         
            +
                def x_report_session
         
     | 
| 
      
 119 
     | 
    
         
            +
                  device.session("X Report") do |s|
         
     | 
| 
      
 120 
     | 
    
         
            +
                    s.notify "X Report Start"
         
     | 
| 
      
 121 
     | 
    
         
            +
                    s.fsend Closure::DAY_FIN_REPORT, "2"
         
     | 
| 
      
 122 
     | 
    
         
            +
                    s.notify "X Report End"
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
                
         
     | 
| 
      
 126 
     | 
    
         
            +
                def cancel_doc_session
         
     | 
| 
      
 127 
     | 
    
         
            +
                  device.session("Doc cancel") do |s|
         
     | 
| 
      
 128 
     | 
    
         
            +
                    s.notify "Doc Cancel Start"
         
     | 
| 
      
 129 
     | 
    
         
            +
                    s.fsend Sales::CANCEL_DOC
         
     | 
| 
      
 130 
     | 
    
         
            +
                    s.notify "Doc Cancel End"
         
     | 
| 
      
 131 
     | 
    
         
            +
                  end
         
     | 
| 
       31 
132 
     | 
    
         
             
                end
         
     | 
| 
       32 
133 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                def  
     | 
| 
       34 
     | 
    
         
            -
                   
     | 
| 
       35 
     | 
    
         
            -
                  #  
     | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
       37 
     | 
    
         
            -
                  #push partial ? "\x1B\x64\x31" : "\x1B\x64\x30"
         
     | 
| 
      
 134 
     | 
    
         
            +
                def check_status
         
     | 
| 
      
 135 
     | 
    
         
            +
                  flush
         
     | 
| 
      
 136 
     | 
    
         
            +
                  fsend(Info::STATUS) # return 6 byte status
         
     | 
| 
      
 137 
     | 
    
         
            +
                  errors.empty?
         
     | 
| 
       38 
138 
     | 
    
         
             
                end
         
     | 
| 
       39 
139 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                 
     | 
| 
       41 
     | 
    
         
            -
                   
     | 
| 
      
 140 
     | 
    
         
            +
                def build_packet(cmd, data = "")
         
     | 
| 
      
 141 
     | 
    
         
            +
                  String.new.tap() do |packet|
         
     | 
| 
      
 142 
     | 
    
         
            +
                    packet << STX
         
     | 
| 
      
 143 
     | 
    
         
            +
                    packet << 0x20 + 4 + data.length
         
     | 
| 
      
 144 
     | 
    
         
            +
                    packet << sequence_number
         
     | 
| 
      
 145 
     | 
    
         
            +
                    packet << cmd
         
     | 
| 
      
 146 
     | 
    
         
            +
                    packet << data
         
     | 
| 
      
 147 
     | 
    
         
            +
                    packet << PA1
         
     | 
| 
      
 148 
     | 
    
         
            +
                    packet << bcc(packet[1..-1])
         
     | 
| 
      
 149 
     | 
    
         
            +
                    packet << ETX
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
                
         
     | 
| 
      
 153 
     | 
    
         
            +
                def fsend!(cmd, data = "") # return data or raise
         
     | 
| 
      
 154 
     | 
    
         
            +
                  push build_packet(cmd, data) # return 6 byte status
         
     | 
| 
      
 155 
     | 
    
         
            +
                  if resp = frecv(RESPONSE_TIMEOUT)
         
     | 
| 
      
 156 
     | 
    
         
            +
                    return resp.data if resp.valid?
         
     | 
| 
      
 157 
     | 
    
         
            +
                  else
         
     | 
| 
      
 158 
     | 
    
         
            +
                    raise errors.full_messages.join(', ')
         
     | 
| 
      
 159 
     | 
    
         
            +
                  end
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
                
         
     | 
| 
      
 162 
     | 
    
         
            +
                def fsend(cmd, data = "") #return data or nil
         
     | 
| 
      
 163 
     | 
    
         
            +
                  packet_data = build_packet(cmd, data)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  result = false
         
     | 
| 
      
 165 
     | 
    
         
            +
                  INVALID_FRAME_RETRIES.times do |retries|
         
     | 
| 
      
 166 
     | 
    
         
            +
                    errors.clear
         
     | 
| 
      
 167 
     | 
    
         
            +
                    push packet_data
         
     | 
| 
      
 168 
     | 
    
         
            +
                    if resp = frecv(RESPONSE_TIMEOUT)
         
     | 
| 
      
 169 
     | 
    
         
            +
                      if resp.valid?
         
     | 
| 
      
 170 
     | 
    
         
            +
                        result = resp.data
         
     | 
| 
      
 171 
     | 
    
         
            +
                        break
         
     | 
| 
      
 172 
     | 
    
         
            +
                      end
         
     | 
| 
      
 173 
     | 
    
         
            +
                    end
         
     | 
| 
      
 174 
     | 
    
         
            +
                    errors.add :base, "#{INVALID_FRAME_RETRIES} Broken Packets Received. Abort!"
         
     | 
| 
      
 175 
     | 
    
         
            +
                  end
         
     | 
| 
      
 176 
     | 
    
         
            +
                  return result
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
                
         
     | 
| 
      
 179 
     | 
    
         
            +
                def frecv(timeout) # return RespFrame or nil
         
     | 
| 
      
 180 
     | 
    
         
            +
                  if frame_bytes = pull(timeout)
         
     | 
| 
      
 181 
     | 
    
         
            +
                    return RespFrame.new(frame_bytes.b)
         
     | 
| 
      
 182 
     | 
    
         
            +
                  else
         
     | 
| 
      
 183 
     | 
    
         
            +
                    errors.add :base, "No data received from device"
         
     | 
| 
      
 184 
     | 
    
         
            +
                    return nil
         
     | 
| 
      
 185 
     | 
    
         
            +
                  end
         
     | 
| 
      
 186 
     | 
    
         
            +
                end
         
     | 
| 
      
 187 
     | 
    
         
            +
               
         
     | 
| 
      
 188 
     | 
    
         
            +
                #private 
         
     | 
| 
      
 189 
     | 
    
         
            +
                  def bcc(buffer)
         
     | 
| 
      
 190 
     | 
    
         
            +
                    sum = 0
         
     | 
| 
      
 191 
     | 
    
         
            +
                    buffer.each_byte do |byte|
         
     | 
| 
      
 192 
     | 
    
         
            +
                      sum += byte
         
     | 
| 
      
 193 
     | 
    
         
            +
                    end
         
     | 
| 
      
 194 
     | 
    
         
            +
                    "".tap() do |bcc|
         
     | 
| 
      
 195 
     | 
    
         
            +
                      4.times do |halfbyte|
         
     | 
| 
      
 196 
     | 
    
         
            +
                        bcc.insert 0, (0x30 + ((sum >> (halfbyte*4)) & 0x0f)).chr
         
     | 
| 
      
 197 
     | 
    
         
            +
                      end
         
     | 
| 
      
 198 
     | 
    
         
            +
                    end
         
     | 
| 
      
 199 
     | 
    
         
            +
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                  
         
     | 
| 
      
 201 
     | 
    
         
            +
                  def sequence_number(increment = true)
         
     | 
| 
      
 202 
     | 
    
         
            +
                    @seq ||= 0x1f
         
     | 
| 
      
 203 
     | 
    
         
            +
                    @seq += 1 if increment
         
     | 
| 
      
 204 
     | 
    
         
            +
                    @seq = 0x1f if @seq == 0x7f
         
     | 
| 
      
 205 
     | 
    
         
            +
                    @seq
         
     | 
| 
      
 206 
     | 
    
         
            +
                  end
         
     | 
| 
      
 207 
     | 
    
         
            +
                  
         
     | 
| 
      
 208 
     | 
    
         
            +
                  def human_status_errors(status) #6 bytes status
         
     | 
| 
      
 209 
     | 
    
         
            +
                    errors.add :base, "Fiscal Device General Error" unless (status[0].ord & 0x20).zero?
         
     | 
| 
      
 210 
     | 
    
         
            +
                    errors.add :base, "Invalid Command" unless (status[0].ord & 0x02).zero?
         
     | 
| 
      
 211 
     | 
    
         
            +
                    errors.add :base, "Date & Time Not Set" unless (status[0].ord & 0x04).zero?
         
     | 
| 
      
 212 
     | 
    
         
            +
                    errors.add :base, "Syntax Error" unless (status[0].ord & 0x02).zero?
         
     | 
| 
      
 213 
     | 
    
         
            +
                    
         
     | 
| 
      
 214 
     | 
    
         
            +
                    errors.add :base, "Wrong Password" unless (status[1].ord & 0x40).zero?
         
     | 
| 
      
 215 
     | 
    
         
            +
                    errors.add :base, "Cutter Error" unless (status[1].ord & 0x20).zero?
         
     | 
| 
      
 216 
     | 
    
         
            +
                    errors.add :base, "Unpermitted Command In This Mode" unless (status[1].ord & 0x02).zero?
         
     | 
| 
      
 217 
     | 
    
         
            +
                    errors.add :base, "Field Overflow" unless (status[1].ord & 0x01).zero?
         
     | 
| 
      
 218 
     | 
    
         
            +
                    
         
     | 
| 
      
 219 
     | 
    
         
            +
                    #errors.add :base, "Print Doc Allowed" unless (status[2].ord & 0x40).zero?
         
     | 
| 
      
 220 
     | 
    
         
            +
                    #errors.add :base, "Non Fiscal Doc Open" unless (status[2].ord & 0x20).zero?
         
     | 
| 
      
 221 
     | 
    
         
            +
                    errors.add :base, "Less Paper (Control)" unless (status[2].ord & 0x20).zero?
         
     | 
| 
      
 222 
     | 
    
         
            +
                    #errors.add :base, "Fiscal Doc Open" unless (status[2].ord & 0x08).zero?
         
     | 
| 
      
 223 
     | 
    
         
            +
                    errors.add :base, "No Paper (Control)" unless (status[2].ord & 0x04).zero?
         
     | 
| 
      
 224 
     | 
    
         
            +
                    errors.add :base, "Less Paper" unless (status[2].ord & 0x02).zero?
         
     | 
| 
      
 225 
     | 
    
         
            +
                    errors.add :base, "No Paper" unless (status[2].ord & 0x01).zero?
         
     | 
| 
       42 
226 
     | 
    
         | 
| 
      
 227 
     | 
    
         
            +
                    case (status[3] & 0x7f)
         
     | 
| 
      
 228 
     | 
    
         
            +
                      when 1 then errors.add :base, "Operation will result in the overflow"
         
     | 
| 
      
 229 
     | 
    
         
            +
                      when 3 then errors.add :base, "No more sales for this doc"
         
     | 
| 
      
 230 
     | 
    
         
            +
                      when 4 then errors.add :base, "No more payments for this doc"
         
     | 
| 
      
 231 
     | 
    
         
            +
                      when 5 then errors.add :base, "Null transaction attempt"
         
     | 
| 
      
 232 
     | 
    
         
            +
                      when 6 then errors.add :base, "Sale not allowed"
         
     | 
| 
      
 233 
     | 
    
         
            +
                      when 7 then errors.add :base, "No rights for this operation"
         
     | 
| 
      
 234 
     | 
    
         
            +
                      when 8 then errors.add :base, "Tax group forbidden"
         
     | 
| 
      
 235 
     | 
    
         
            +
                      when 11 then errors.add :base, "Multiple decimal points"
         
     | 
| 
      
 236 
     | 
    
         
            +
                      when 12 then errors.add :base, "Multiple sign symbols"
         
     | 
| 
      
 237 
     | 
    
         
            +
                      when 13 then errors.add :base, "Sign not at first position"
         
     | 
| 
      
 238 
     | 
    
         
            +
                      when 14 then errors.add :base, "Wrong symbol"
         
     | 
| 
      
 239 
     | 
    
         
            +
                      when 15 then errors.add :base, "Too many symbols after decimal point"
         
     | 
| 
      
 240 
     | 
    
         
            +
                      when 16 then errors.add :base, "Too many symbols"
         
     | 
| 
      
 241 
     | 
    
         
            +
                      when 20 then errors.add :base, "Service not allowed"
         
     | 
| 
      
 242 
     | 
    
         
            +
                      when 21 then errors.add :base, "Wrong Value"
         
     | 
| 
      
 243 
     | 
    
         
            +
                      when 22 then errors.add :base, "Disabled operation"
         
     | 
| 
      
 244 
     | 
    
         
            +
                      when 23 then errors.add :base, "Deep void after discount"
         
     | 
| 
      
 245 
     | 
    
         
            +
                      when 24 then errors.add :base, "Deep void for not existing record"
         
     | 
| 
      
 246 
     | 
    
         
            +
                      when 24 then errors.add :base, "Payment without sale"
         
     | 
| 
      
 247 
     | 
    
         
            +
                    end
         
     | 
| 
      
 248 
     | 
    
         
            +
                    
         
     | 
| 
      
 249 
     | 
    
         
            +
                    errors.add :base, "General Fiscal Memory Error" unless (status[4].ord & 0x20).zero?
         
     | 
| 
      
 250 
     | 
    
         
            +
                    errors.add :base, "Fiscal Memory Full" unless (status[4].ord & 0x10).zero?
         
     | 
| 
      
 251 
     | 
    
         
            +
                    errors.add :base, "Less Than 50 Fiscal Records" unless (status[4].ord & 0x08).zero?
         
     | 
| 
      
 252 
     | 
    
         
            +
                    errors.add :base, "Invalid Fiscal Records" unless (status[4].ord & 0x04).zero?
         
     | 
| 
      
 253 
     | 
    
         
            +
                    errors.add :base, "Fiscal Write Error" unless (status[4].ord & 0x01).zero?
         
     | 
| 
      
 254 
     | 
    
         
            +
                    
         
     | 
| 
      
 255 
     | 
    
         
            +
                    #errors.add :base, "Fiscal Memory Ready" unless (status[5].ord & 0x40).zero?
         
     | 
| 
      
 256 
     | 
    
         
            +
                    #errors.add :base, "Fiscal ID Set" unless (status[5].ord & 0x20).zero?
         
     | 
| 
      
 257 
     | 
    
         
            +
                    #errors.add :base, "Fiscal Tax set" unless (status[5].ord & 0x10).zero?
         
     | 
| 
      
 258 
     | 
    
         
            +
                    #errors.add :base, "Real Sales Mode" unless (status[5].ord & 0x80).zero?
         
     | 
| 
      
 259 
     | 
    
         
            +
                    errors.add :base, "Fiscal Memory Full" unless (status[5].ord & 0x01).zero?
         
     | 
| 
       43 
260 
     | 
    
         
             
                  end
         
     | 
| 
       44 
261 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
                   
     | 
| 
       46 
     | 
    
         
            -
                     
     | 
| 
       47 
     | 
    
         
            -
                    data 
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 262 
     | 
    
         
            +
                  class RespFrame
         
     | 
| 
      
 263 
     | 
    
         
            +
                    include ActiveModel::Validations
         
     | 
| 
      
 264 
     | 
    
         
            +
                    attr_reader :frame, :len, :seq, :cmd, :data, :status, :bcc
         
     | 
| 
      
 265 
     | 
    
         
            +
                    
         
     | 
| 
      
 266 
     | 
    
         
            +
                    validates_presence_of :frame
         
     | 
| 
      
 267 
     | 
    
         
            +
                    #validate :bcc_validation
         
     | 
| 
      
 268 
     | 
    
         
            +
                    #validate :len_validation
         
     | 
| 
      
 269 
     | 
    
         
            +
                    
         
     | 
| 
      
 270 
     | 
    
         
            +
                    def initialize(buffer)
         
     | 
| 
      
 271 
     | 
    
         
            +
                      # test Extface::Driver::DaisyFx1200::RespFrame.new("\x16\x16\x01\x2c\x20\x2dP\x04SSSSSS\x05\BBBB\x03")
         
     | 
| 
      
 272 
     | 
    
         
            +
                      #                              LEN   SEQ   CMD DATA    STATUS      BCC
         
     | 
| 
      
 273 
     | 
    
         
            +
                      if match = buffer.match(/\x01(.{1})(.{1})(.{1})(.*)\x04(.{6})\x05(.{4})\x03/n)
         
     | 
| 
      
 274 
     | 
    
         
            +
                        @frame = match.string[match.pre_match.length..-1]
         
     | 
| 
      
 275 
     | 
    
         
            +
                        @len, @seq, @cmd, @data, @status, @bcc = match.captures
         
     | 
| 
      
 276 
     | 
    
         
            +
                      end
         
     | 
| 
       49 
277 
     | 
    
         
             
                    end
         
     | 
| 
      
 278 
     | 
    
         
            +
                    
         
     | 
| 
      
 279 
     | 
    
         
            +
                    private
         
     | 
| 
      
 280 
     | 
    
         
            +
                      def bcc_validation
         
     | 
| 
      
 281 
     | 
    
         
            +
                        sum = 0
         
     | 
| 
      
 282 
     | 
    
         
            +
                        frame[1..-6].each_byte do |byte|
         
     | 
| 
      
 283 
     | 
    
         
            +
                          sum += byte
         
     | 
| 
      
 284 
     | 
    
         
            +
                        end
         
     | 
| 
      
 285 
     | 
    
         
            +
                        calc_bcc = "".tap() do |tbcc|
         
     | 
| 
      
 286 
     | 
    
         
            +
                          4.times do |halfbyte|
         
     | 
| 
      
 287 
     | 
    
         
            +
                            tbcc.insert 0, (0x30 + ((sum >> (halfbyte*4)) & 0x0f)).chr
         
     | 
| 
      
 288 
     | 
    
         
            +
                          end
         
     | 
| 
      
 289 
     | 
    
         
            +
                        end
         
     | 
| 
      
 290 
     | 
    
         
            +
                        errors.add(:bcc, I18n.t('errors.messages.invalid')) if bcc != calc_bcc
         
     | 
| 
      
 291 
     | 
    
         
            +
                      end
         
     | 
| 
      
 292 
     | 
    
         
            +
                      
         
     | 
| 
      
 293 
     | 
    
         
            +
                      def len_validation
         
     | 
| 
      
 294 
     | 
    
         
            +
                        errors.add(:len, I18n.t('errors.messages.invalid')) if len.ord != (frame[1..-6].length + 0x20)
         
     | 
| 
      
 295 
     | 
    
         
            +
                      end
         
     | 
| 
       50 
296 
     | 
    
         
             
                  end
         
     | 
| 
       51 
297 
     | 
    
         
             
              end
         
     | 
| 
       52 
298 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,4 +1,76 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Extface
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Driver::Epson::Fiscal
         
     | 
| 
      
 3 
     | 
    
         
            +
                STX = 0x02
         
     | 
| 
      
 4 
     | 
    
         
            +
                ETX = 0x03
         
     | 
| 
      
 5 
     | 
    
         
            +
                SEP = 0x1c
         
     | 
| 
      
 6 
     | 
    
         
            +
                DC2 = 0x12
         
     | 
| 
      
 7 
     | 
    
         
            +
                DC4 = 0x14
         
     | 
| 
      
 8 
     | 
    
         
            +
                NAK = 0x15
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                module Control
         
     | 
| 
      
 11 
     | 
    
         
            +
                  STATUS_IF             = 0x38
         
     | 
| 
      
 12 
     | 
    
         
            +
                  X_Z_REPORTS           = 0x39
         
     | 
| 
      
 13 
     | 
    
         
            +
                  FISC_MEM_REPORT_DATE  = 0x3a
         
     | 
| 
      
 14 
     | 
    
         
            +
                  FISC_MEM_REPORT       = 0x3b
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
                module Vouchers
         
     | 
| 
      
 17 
     | 
    
         
            +
                  OPEN_FISCAL_VOUCHER   = 0x40
         
     | 
| 
      
 18 
     | 
    
         
            +
                  PRINT_FISCAL_TEXT     = 0x41
         
     | 
| 
      
 19 
     | 
    
         
            +
                  PRINT_FISCAL_ARTICLE  = 0x42
         
     | 
| 
      
 20 
     | 
    
         
            +
                  SUBTOTAL_FISCAL       = 0x43
         
     | 
| 
      
 21 
     | 
    
         
            +
                  FISCAL_VOUCHER        = 0x44  # pay / cancel / discount in
         
     | 
| 
      
 22 
     | 
    
         
            +
                  CLOSE_FISCAL_VOUCHER  = 0x45
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
                module NonFiscal
         
     | 
| 
      
 25 
     | 
    
         
            +
                  OPEN_NON_FISCAL_DOC   = 0x48
         
     | 
| 
      
 26 
     | 
    
         
            +
                  PRINT_NON_FISCAL_TEXT = 0x49
         
     | 
| 
      
 27 
     | 
    
         
            +
                  CLOSE_NON_FISCAL_DOC  = 0x4a
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
                module Printer
         
     | 
| 
      
 30 
     | 
    
         
            +
                  CUT_PAPER         = 0x4b
         
     | 
| 
      
 31 
     | 
    
         
            +
                  ADVANCE_PAPER     = 0x50
         
     | 
| 
      
 32 
     | 
    
         
            +
                  ACTIVATE_SLIP     = 0xa0 #TMU950, TMU675
         
     | 
| 
      
 33 
     | 
    
         
            +
                  DISABLE_SLIP      = 0xa1
         
     | 
| 
      
 34 
     | 
    
         
            +
                  FORMAT_CHECKS     = 0xaa
         
     | 
| 
      
 35 
     | 
    
         
            +
                  FORMAT_ENDOSEMENT = 0xab
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
                module General
         
     | 
| 
      
 38 
     | 
    
         
            +
                  SET_DATE_HOUR   = 0x58
         
     | 
| 
      
 39 
     | 
    
         
            +
                  GET_DATE_HOUR   = 0x59
         
     | 
| 
      
 40 
     | 
    
         
            +
                  HEADED          = 0x5d
         
     | 
| 
      
 41 
     | 
    
         
            +
                  FOOT_OF_PAGE    = 0x5e
         
     | 
| 
      
 42 
     | 
    
         
            +
                  OPEN_DRAWER_1   = 0x7b
         
     | 
| 
      
 43 
     | 
    
         
            +
                  OPEN_DRAWER_2   = 0x7c
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def build_packet(cmd, fields = [])
         
     | 
| 
      
 47 
     | 
    
         
            +
                  String.new.tap() do |frame|
         
     | 
| 
      
 48 
     | 
    
         
            +
                    frame << STX
         
     | 
| 
      
 49 
     | 
    
         
            +
                    frame << sequence_number
         
     | 
| 
      
 50 
     | 
    
         
            +
                    frame << cmd
         
     | 
| 
      
 51 
     | 
    
         
            +
                    fields.each do |field|
         
     | 
| 
      
 52 
     | 
    
         
            +
                      frame << SEP
         
     | 
| 
      
 53 
     | 
    
         
            +
                      frame << field
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                    frame << ETX
         
     | 
| 
      
 56 
     | 
    
         
            +
                    frame << bcc(frame)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                private
         
     | 
| 
      
 61 
     | 
    
         
            +
                  def bcc(buffer)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    sum = 0
         
     | 
| 
      
 63 
     | 
    
         
            +
                    buffer.each_byte do |b|
         
     | 
| 
      
 64 
     | 
    
         
            +
                      sum += b
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
                    sum.to_s(16).rjust(4, '0')
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  
         
     | 
| 
      
 69 
     | 
    
         
            +
                  def sequence_number(increment = true)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    @seq ||= 0x20
         
     | 
| 
      
 71 
     | 
    
         
            +
                    @seq += 1 if increment
         
     | 
| 
      
 72 
     | 
    
         
            +
                    @seq = 0x20 if @seq == 0x7f
         
     | 
| 
      
 73 
     | 
    
         
            +
                    @seq
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end 
         
     | 
| 
       3 
75 
     | 
    
         
             
              end
         
     | 
| 
       4 
76 
     | 
    
         
             
            end
         
     | 
| 
         @@ -69,6 +69,13 @@ 
     | 
|
| 
       69 
69 
     | 
    
         
             
            <% if @device.print? %>
         
     | 
| 
       70 
70 
     | 
    
         
             
              <%= button_to 'Print Test Page', test_page_device_path(@device), remote: true, name: :test_page, value: true, class: 'btn btn-warning' %>
         
     | 
| 
       71 
71 
     | 
    
         
             
            <% end %>
         
     | 
| 
      
 72 
     | 
    
         
            +
            <% if @device.fiscal? %>
         
     | 
| 
      
 73 
     | 
    
         
            +
              <%= button_to 'Non Fiscal Test', fiscal_device_path(@device), remote: true, name: :non_fiscal_test, value: true, class: 'btn btn-warning' %>
         
     | 
| 
      
 74 
     | 
    
         
            +
              <%= button_to 'Fiscal Test', fiscal_device_path(@device), remote: true, name: :fiscal_test, value: true, class: 'btn btn-warning' %>
         
     | 
| 
      
 75 
     | 
    
         
            +
              <%= button_to 'X Report', fiscal_device_path(@device), remote: true, name: :x_report, value: true, class: 'btn btn-warning' %>
         
     | 
| 
      
 76 
     | 
    
         
            +
              <%= button_to 'Z Report', fiscal_device_path(@device), remote: true, name: :z_report, value: true, class: 'btn btn-warning' %>
         
     | 
| 
      
 77 
     | 
    
         
            +
              <%= button_to 'Cancel Fiscal Doc', fiscal_device_path(@device), remote: true, name: :cancel_fiscal_doc, value: true, class: 'btn btn-warning' %>
         
     | 
| 
      
 78 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       72 
79 
     | 
    
         | 
| 
       73 
80 
     | 
    
         
             
            <br />Simulate push data from device
         
     | 
| 
       74 
81 
     | 
    
         | 
    
        data/config/routes.rb
    CHANGED
    
    
    
        data/lib/extface/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: extface
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.8
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Alex Vangelov
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2014-05- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2014-05-17 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: rails
         
     |