Class: Driver::Datecs::Fp550

Inherits:
Extface::Driver::Base::Fiscal
  • Object
show all
Includes:
Extface::Driver::Datecs::CommandsV1
Defined in:
app/models/extface/driver/datecs/fp550.rb

Defined Under Namespace

Classes: Frame

Constant Summary collapse

NAME =
'Datecs FP550 (Serial)'.freeze
RESPONSE_TIMEOUT =

seconds

3
INVALID_FRAME_RETRIES =

count (bad length, bad checksum)

6
ACKS_MAX_WAIT =

count / nothing is forever

60
NAKS_MAX_COUNT =

count

3

Instance Method Summary collapse

Instance Method Details

#add_comment(text) ⇒ Object



96
97
98
# File 'app/models/extface/driver/datecs/fp550.rb', line 96

def add_comment(text)
  raise "Not in fiscal session" unless @fiscal_session
end

#add_payment(value = nil, type_num = nil) ⇒ Object



100
101
102
103
104
105
106
107
108
# File 'app/models/extface/driver/datecs/fp550.rb', line 100

def add_payment(value = nil, type_num = nil)
  raise "Not in fiscal session" unless @fiscal_session
  payment_data = "".tap() do |data|
                        data << "\t"
                        data << PAYMENT_TYPE_MAP[type_num || 1]
                        data << ("%.2f" % value) unless value.blank?
                      end
  fsend(Sales::TOTAL, payment_data)
end

#add_sale(sale_item) ⇒ Object



91
92
93
94
# File 'app/models/extface/driver/datecs/fp550.rb', line 91

def add_sale(sale_item)
  raise "Not in fiscal session" unless @fiscal_session
  fsend Sales::SALE_AND_SHOW, build_sale_data(sale_item)
end

#build_packet(cmd, data = "") ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
# File 'app/models/extface/driver/datecs/fp550.rb', line 190

def build_packet(cmd, data = "")
  "".b.tap() do |packet|
    packet << STX                     #Preamble. 1 byte long. Value: 01H.
    packet << 0x20 + 4 + data.length  #Number of bytes from <01> preamble (excluded) to <05> (included) plus the fixed offset of 20H
    packet << sequence_number         #Sequence number of the frame. Length : 1 byte. Value: 20H – FFH.
    packet << cmd                     #Length: 1 byte. Value: 20H - 7FH.
    packet << data                    #Length: 0 - 218 bytes for Host to printer
    packet << PA1                     #Post-amble. Length: 1 byte. Value: 05H.
    packet << Frame.bcc(packet[1..-1])#Control sum (0000H-FFFFH). Length: 4 bytes. Value of each byte: 30H-3FH
    packet << ETX                     #Terminator. Length: 1 byte. Value: 03H.
  end
end

#cancel_doc_session ⇒ Object



132
133
134
135
136
137
138
139
# File 'app/models/extface/driver/datecs/fp550.rb', line 132

def cancel_doc_session
  device.session("Doc cancel") do |s|
    s.notify "Doc Cancel Start"
    s.fsend Sales::CANCEL_DOC
    s.paper_cut
    s.notify "Doc Cancel End"
  end
end

#check_status ⇒ Object



73
74
75
76
77
# File 'app/models/extface/driver/datecs/fp550.rb', line 73

def check_status
  flush #clear receive buffer
  fsend(Info::GET_STATUS, 'X') # get 6 bytes status
  errors.empty?
end

#close_fiscal_doc ⇒ Object



85
86
87
88
89
# File 'app/models/extface/driver/datecs/fp550.rb', line 85

def close_fiscal_doc
  raise "Not in fiscal session" unless @fiscal_session
  fsend Sales::END_FISCAL_DOC
  @fiscal_session = false
end

#close_non_fiscal_doc ⇒ Object



68
69
70
71
# File 'app/models/extface/driver/datecs/fp550.rb', line 68

def close_non_fiscal_doc
  fsend Sales::END_NON_FISCAL_DOC
  @print_session = false
end

#fiscal_test ⇒ Object



34
35
36
37
38
# File 'app/models/extface/driver/datecs/fp550.rb', line 34

def fiscal_test
  sale_and_pay_items_session([
    SaleItem.new( price: 0.01, text1: "Extface Test" )
  ])
end

#frecv(timeout) ⇒ Object

return RespFrame or nil



181
182
183
184
185
186
187
188
# File 'app/models/extface/driver/datecs/fp550.rb', line 181

def frecv(timeout) # return RespFrame or nil
  if frame_bytes = pull(timeout)
    return Frame.new(frame_bytes.b)
  else
    errors.add :base, "No data received from device"
    return nil
  end
end

#fsend(cmd, data = "") ⇒ Object

common



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'app/models/extface/driver/datecs/fp550.rb', line 142

def fsend(cmd, data = "") #return data or nil
  packet_data = build_packet(cmd, data) #store packet to be able to re-transmit it with the same sequence number
  result = false
  invalid_frames = 0 #counter for bad responses
  nak_messages = 0 #counter for rejected packets (should re-transmit the packet)
  push packet_data #send packet
  ACKS_MAX_WAIT.times do |retries|
    errors.clear
    if resp = frecv(RESPONSE_TIMEOUT)
      if resp.valid?
        human_status_errors(resp.status)
        if errors.empty?
          result = resp.data
          break
        else
          raise errors.full_messages.join(',')
        end
      else #ack, nak or bad
        if resp.nak?
          nak_messages += 1
          if nak_messages > NAKS_MAX_COUNT
            errors.add :base, "#{NAKS_MAX_COUNT} NAKs Received. Abort!"
            break
          end
        elsif !resp.ack?
          invalid_frames += 1
          if nak_messages > INVALID_FRAME_RETRIES
            errors.add :base, "#{INVALID_FRAME_RETRIES} Broken Packets Received. Abort!"
            break
          end
        end
        push packet_data unless resp.ack?
      end
    end
    errors.add :base, "#{ACKS_MAX_WAIT} ACKs Received. Abort!"
  end
  return result
end

#handle(buffer) ⇒ Object



12
13
14
15
16
17
# File 'app/models/extface/driver/datecs/fp550.rb', line 12

def handle(buffer)
  if i = buffer.index(/[\x03\x16\x15]/)   # find position of frame possible delimiter
    rpush buffer[0..i]                    # this will make data available for #pull(timeout) method
    return i+1                            # return number of bytes processed
  end
end

#human_status_errors(status) ⇒ Object

6 bytes status



209
210
211
212
213
214
215
216
# File 'app/models/extface/driver/datecs/fp550.rb', line 209

def human_status_errors(status) #6 bytes status
  status_0 = status[0].ord
  errors.add :base, "Fiscal Device General Error" unless (status_0 & 0x20).zero?
  errors.add :base, "Invalid Command" unless (status_0 & 0x02).zero?
  errors.add :base, "Date & Time Not Set" unless (status_0 & 0x04).zero?
  errors.add :base, "Syntax Error" unless (status_0 & 0x02).zero?
  status_1 = status[1].ord
end

#non_fiscal_test ⇒ Object

tests



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'app/models/extface/driver/datecs/fp550.rb', line 20

def non_fiscal_test
  device.session("Non Fiscal Text") do |s|
    s.notify "Printing Non Fiscal Text"
    s.open_non_fiscal_doc
    s.print "********************************"
    s.print "Extface Print Test".center(32)
    s.print "********************************"
    s.fsend Printer::PAPER_MOVE, "1"
    s.print "Driver: " + "#{self.class::NAME}".truncate(24)
    s.close_non_fiscal_doc
    s.notify "Printing finished"
  end
end

#open_fiscal_doc(operator = "1", password = "1") ⇒ Object

fiscal



80
81
82
83
# File 'app/models/extface/driver/datecs/fp550.rb', line 80

def open_fiscal_doc(operator = "1", password = "1")
  fsend Sales::START_FISCAL_DOC, "#{operator.presence || "1"},#{password.presence || "1"},00001"
  @fiscal_session = true
end

#open_non_fiscal_doc ⇒ Object

print



58
59
60
61
# File 'app/models/extface/driver/datecs/fp550.rb', line 58

def open_non_fiscal_doc
  fsend Sales::START_NON_FISCAL_DOC
  @print_session = true
end

#paper_cut ⇒ Object



203
204
205
206
207
# File 'app/models/extface/driver/datecs/fp550.rb', line 203

def paper_cut
  device.session('Paper Cut') do |s|
    s.push build_packet(Printer::PAPER_CUT)
  end
end

up to 38 sybols, TODO check



63
64
65
66
# File 'app/models/extface/driver/datecs/fp550.rb', line 63

def print(text) #up to 38 sybols, TODO check
  raise "Not in print session" unless @print_session
  fsend Sales::PRINT_NON_FISCAL_TEXT, text
end

#sale_and_pay_items_session(items = [], operator = "1", password = "1") ⇒ Object

basket



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'app/models/extface/driver/datecs/fp550.rb', line 116

def sale_and_pay_items_session(items = [], operator = "1", password = "1")
  device.session("Fiscal Doc") do |s|
    s.notify "Fiscal Doc Start"
    s.open_fiscal_doc
    s.notify "Register Sale"
    items.each do |item|
      s.add_sale(item)
    end
    s.notify "Register Payment"
    s.total_payment
    s.notify "Close Fiscal Receipt"
    s.close_fiscal_doc
    s.notify "Fiscal Doc End"
  end
end

#total_payment ⇒ Object



110
111
112
113
# File 'app/models/extface/driver/datecs/fp550.rb', line 110

def total_payment
  raise "Not in fiscal session" unless @fiscal_session
  fsend(Sales::TOTAL, "\t")
end

#x_report_session ⇒ Object



49
50
51
52
53
54
55
# File 'app/models/extface/driver/datecs/fp550.rb', line 49

def x_report_session
  device.session("X Report") do |s|
    s.notify "X Report Start"
    s.fsend Closure::DAY_FIN_REPORT, "2"
    s.notify "X Report End"
  end
end

#z_report_session ⇒ Object

reports



41
42
43
44
45
46
47
# File 'app/models/extface/driver/datecs/fp550.rb', line 41

def z_report_session
  device.session("Z Report") do |s|
    s.notify "Z Report Start"
    s.fsend Closure::DAY_FIN_REPORT, "0"
    s.notify "Z Report End"
  end
end